岩本隆史の日記帳(アーカイブ)

はてなダイアリーのサービス終了をうけて移行したものです。更新はしません。

WebアプリケーションフレームワークにおけるHTTPステータスコードの扱い方

最近、HTTPやらWADLやらMVCやらについて考えていたのは、Webアプリケーションフレームワーク*1を自作する*2うえで必要な作業だったからでした。方向性は見えてきた(と思いたい)ので、今回は「フレームワークにおいてHTTPステータスコードをどう扱うべきか」について考えてみます。

さきに断っておきますが、「HTTPステータスコードをどう扱うべきか」はフレームワークの数だけ答えがあると私は思っています。これから書くのは個人的な好みによる設計判断であることをご了承ください。

Alan Dean氏の図はしっくりこない

どのような状況でどのようなHTTPステータスコードを返すべきかについてAlan Dean氏がまとめたダイアグラムがあります。一見、この図をそのままフレームワークに適用すれば考えるまでもないように思えるのですが、下記の2点から、どうも私にはしっくりこないのです。

  • 認証状況の確認フェーズが早くないか。他の4xx系エラーより先に「401 Unauthorized」を返してもしかたないように思える。そのような意識の違いが随所にある。
  • 「414 Request URI Too Long」など、Webサーバに任せたい処理内容が含まれている。

したがって、図が正しいか正しくないかはともかく、私のフレームワークへの適用はできないと考えています。

ディスパッチャレベルの処理フロー

それでは、私がどのように考えているか、記してみます。

まずは、ディスパッチャレベル(コントローラ確定前の段階)の処理フローです。

  1. 例外を捕捉する。例外が起きたら「500 Internal Server Error」を返す。
  2. メンテ中かどうか確認する。メンテ中なら「503 Service Unavailable」を返す。
  3. リクエストされたURIが存在しえるかどうか確認する。存在しえなければ「400 Bad Request」を返す。
  4. コントローラを確定、処理を委譲する。

3がややこしいかもしれませんが、おもに新規PUTを想定しています。つまり、リソースがまだないURIへのPUTについて、URIが有効であれば通すが、無効であればはじきたいということです。GETなどの他のメソッドであれば「404 Not Found」を返すのが自然なのかもしれませんが、そこまでこだわらなくてもよいと考えています。

コントローラレベルの処理フロー

次に、コントローラレベル(コントローラ確定後の段階)の処理フローです。

  1. リソースがあるか確認する。なければ「404 Not Found」を返す(GET、HEAD、POST、DELETEのみ)。
  2. リクエスURIに対して有効なメソッドかどうか確認する。無効なら「405 Method Not Allowed」を返す。
  3. リクエストボディのメディアタイプが有効かどうか確認する。無効なら「415 Unsupported Media Type」を返す(POST、PUTのみ)。
  4. 入力値のバリデーション。無効な値があれば「400 Bad Request」を返す。
  5. 「If-Match」や「If-Unmodified-Since」をチェックする。一致しなければ「412 Precondition Failed」を返す。
  6. 認証が必要なのに未認証ではないか確認する。「401 Unauthorized」を返す(OPTIONS以外)。
  7. 「If-None-Match」や「If-Modified-Since」をチェックする。一致したら「304 Not Modified」(GET、HEAD)か「412 Precondition Failed」(GET、HEAD以外)を返す。
  8. 処理成功。「200 OK」「201 Created」「202 Accepted」「300 Multiple Choices」「303 See Other」のいずれかを状況に応じて返す。

7の「If-None-Match」「If-Modified-Since」チェックは、GETやHEAD以外のメソッドであれば無視してよいかもしれません。それ以外のメソッドでは、まず使われないでしょう。

あくまで叩き台

「あのステータスコードはどうした」とか「処理の順番がおかしいんじゃないか」とか、いろいろご意見があるかもしれません。私の想定するフレームワークの挙動に合わせ、なるべく簡潔な処理になるよう考慮したものですが、あくまでひとつの案なので、叩き台として参照いただければ幸いです。私もまだまだ練るつもりです。

*1:もっと短く書きたいのですが、「WAF」と略すと「Webアプリケーションファイアウォール」と誤解される可能性があります。

*2:既存のフレームワークが多々あるのにわざわざ自作するのは「既存フレームワーク使いたくない病」に私が冒されているからです。ご愁傷様です。