LoginSignup
8
3

More than 3 years have passed since last update.

Land of Lisp 13章(Web サーバを作ろう!)でhello-request-handlerを正しく表示する方法

Last updated at Posted at 2020-01-23

2020年2月3日追記:コードの後半を修正、19章のdod-request-handlerの記述を追加)

現象

Land of Lispの13章は、ローカルでWebサイトを立ち上げることが目標になっているが、リクエストハンドラを本に載っている通り以下のコードを書いてしまうと、2020年現在、macOS Catalina環境下では、Chromeでは「127.0.0.1 から無効な応答が送信されました(ERR_INVALID_HTTP_RESPONSE)」というエラーが返ってきてしまい、FirefoxではHTMLコードがそのまま画面に表示されてしまう。
15章以降では、Webサーバが正しく立ち上がる前提で話が進むので、ここで詰まってしまうとコードを走らせることができなくなってしまう。

(defun hello-request-handler (path header params)
  (if (equal path "greeting")
      (let ((name (assoc 'name params)))
    (if (not name)
        (princ "<html><form>What is your name?<input name='name' />
</form></html>")
        (format t "<html>Nice to meet you, ~a!</html>" (cdr name))))
      (princ "Sorry... I don't know that page.")))

解決法

以下の記事で起きている現象と性質は同様で、解決法も同じであった(lambdacadabraさんに深謝)。
https://lambdacadabra.blogspot.com/2016/11/land-of-lispwebfirefox.html
主要なコードの変更点は、HTMLコードの前にレスポンス行と改行を2つ出力するようにしたという点。
それに応じて、URL相違の際に表示されるテキストの前後にもhtmlタグを追加している。
これで、Chrome, Firefoxいずれでも正しく表示されるようになった。
記事中では「ChromeではHTMLがきちんと解釈されて入力フォームなどが普通に表示される」とあるが、記事投稿時(2016年)の後Chromeの仕様変更があり、エラーを吐くようになったのかもしれない。

(defun hello-request-handler (path header params)
  (if (equal path "greeting")
      (let ((name (assoc 'name params)))
    (if (not name)
        (progn ; 追加
          (princ "HTTP/1.1 200 OK") ; 追加
          (terpri) ; 追加
          (terpri) ; 追加
          (princ "<html><form>What is your name?<input name='name' />
</form></html>"))
        (progn ; 追加
          (princ "HTTP/1.1 200 OK") ; 追加
          (terpri) ; 追加
          (terpri) ; 追加
          (format t "<html>Nice to meet you, ~a!</html>" (cdr name)))))
      (progn ;; Added
        (princ "HTTP/1.1 200 OK") ;; 追加
        (terpri) ;; 追加
        (terpri) ;; 追加
        (princ "<html>Sorry... I don't know that page.</html>")))) ;; 変更

参考:19章に登場する同様のハンドラ(dod-request-handler)の修正方法

19章で書くDice of Doomのハンドラにも同様の変更が必要なので、下記に変更後のコードを記しておく。

(defun dod-request-handler (path header params)
  (if (equal path "game.html")
      (progn (princ "HTTP/1.1 200 OK") ;; 追加
         (terpri) ;; 追加
         (terpri) ;; 追加
         (princ "<!doctype html>")
         (tag center ()
           (princ "Welcome to DICE OF DOOM!")
           (tag br ())
           (let ((chosen (assoc 'chosen params)))
         (when (or (not *cur-game-tree*) (not chosen))
           (setf chosen nil)
           (web-initialize))
         (cond ((lazy-null (caddr *cur-game-tree*))
            (web-announce-winner (cadr *cur-game-tree*)))
               ((zerop (car *cur-game-tree*))
            (web-handle-human
             (when chosen
               (read-from-string (cdr chosen)))))
               (t (web-handle-computer))))
           (tag br ())
           (draw-dod-page *cur-game-tree* *from-tile*)))
      (progn (princ "HTTP/1.1 200 OK") ;; 追加
         (terpri) ;; 追加
         (terpri) ;; 追加
         (princ "<html>Sorry... I don't know that page.</html>")))) ;; 変更
8
3
3

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
8
3