wvogel日記

自分用の技術備忘録が多めです.

HaskellチャットサーバでCSSやJSリクエストを返す

Haskellでチャットサーバを立てる記事( Haskellでチャットサーバーを建ててみた - Qiita )を読んで,私も試してみたくなりました

この記事のプログラムは昔MakerFaireに出した時にも参考にしていて,一度websocketを使った通信は書いたことがあるのですが,
当時はよく理解しないまま書いて,最後時間に追われバグ取りも友人にやってもらっていました.

とはいえ今回はチャットサーバ書くだけですから写経で良いわけです.
ただ入力フォームしかないのは寂しいので,jsとcssを書いて,それなりにアプリらしい外観にします.

しかしその場合,ただプログラムを写経しただけでは動作しません.
ブラウザの開発者用ツールを見ればわかると思いますが,jsやcssファイルの読み込みに失敗します.
これは,クライアントがサーバーにアクセスしてhtmlを呼び出した後に順番にやってくる,htmlから呼び出される他のファイルに関するリクエストを全無視しているからです.
これらのファイル呼び出しリクエストも処理してやらねばなりません.

こういう時には,pathInfo関数を使ってリクエストの中身を調べることが出来ます.

pathInfo :: Request -> [Text]

リクエストの情報を知ることが出来ます.これでリクエストの中身を見ると,次のような結果を得ることが出来ます

-- 一番最初,サーバーにアクセスしてきた時
pathInfo req
[]

-- html中の<script type="text/javascript" src="js/test.js"></script>に関してリクエストを受けた時
pathInfo req
["js", "test.js"]

このリクエスト内容に合ったレスポンスを返してやれば,cssやjsで着飾ったサイトを表示することが出来ます.
変更するのは,参考記事のうち,app関数だけです.例えば次のように変更します.

app :: Appplication
app req respond = do
    case pathInfo req of
        [] -> respond $ serveFile "text/html" "index.html"
        ["js", js] -> respond.serveFile "text/javascript" $ "js/" ++ unpack js
        ["css", css] -> respond.serveFile "text/css" $ "css/" ++ unpack css
        ["img", img] -> respond.serveFile "image/png" $ "img/" ++ unpack img

serveFile mime filePath = responseFile status200 [("Content-Type",mime)] filePath Nothing

pathInfoの返す値はTextのリストなので,適宜Data.Text.unpackでStringに戻します.
Mimeの部分も,下記URLなどを参考に,返すファイル内容によって変更してください.
拡張子とMIMEタイプ - とほほのWWW入門