前回に引き続き、『Webを支える技術』を読んで、気になった箇所を簡潔にまとめる(第9章 「HTTPヘッダ」のみ)。
■ HTTPヘッダの重要性
- ヘッダはメッセージのボディに対する付加的な情報、いわゆるメタデータを表現する
- クライアントやサーバはヘッダを見て、メッセージに対する挙動を決定する
- 認証やキャッシュなどの機能は、ヘッダをメソッドやステータスコードと組み合わせて初めて実現できる
■ HTTPヘッダの生い立ち
- HTTPの最初のバージョンにはヘッダが存在しなかった
- HTTPのヘッダは電子メールのメッセージ仕様のヘッダ形式を借りてくる形で追加された。そのため、HTTPヘッダには電子メールのメッセージヘッダと共通する部分がある
- 電子メールとHTTPメソッドの最も大きな違いは、メールプロトコルが一方向にしかメッセージをやりとりしないのに対して、HTTPは一度の通信でリクエストとレスポンスの2つのメッセージをやりとりする点である
■ 日時
利用するメッセージ | ヘッダ | 意味 |
---|---|---|
リクエストとレスポンス | Date | メッセージを生成した日時 |
リクエスト | If-Modified-Since | 条件付きGETでリソースの更新日時を指定する時に利用する |
リクエスト | If-Unmodified-Since | 条件付きPUTや条件付きDELETEでリソースの更新日時を指定する時に利用する |
レスポンス | Expires | レスポンスをキャッシュできる期限 |
レスポンス | Last-Modified | リソースを最後に更新した日時 |
レスポンス | Retry-After | 再度リクエストを送信できるようになる日時の目安 |
■ MIMEメディアタイプ
- メッセージでやりとりするリソースの表現の種類を指定するのがMIMEメディアタイプである
- この仕様も、電子メールから拝借してきたものである
- Content-TypeヘッダはMIMEメディアタイプを指定する。メッセージのボディの内容がどのような種類なのかをメディアタイプで示す。
- Content-Typeにはタイプとサブタイプがある。タイプはRFCにより定められた9つがある。サブタイプは比較的自由に増やすことが可能。
タイプ一覧(全9こ)
タイプ | 意味 | 例 |
---|---|---|
text | 人が読んで直接理解できるテキスト | text/plain |
image | 画像データ | image/jpeg |
audio | 音声データ | audio/mpeg |
video | 映像データ | video/mp4 |
application | そのほかのデータ | application/pdf |
multipart | 複数のデータからなる複合データ | multipart/related |
message | 電子メールメッセージ | message/rfc822 |
model | 複数次元で構成するモデルデータ | model/vrml |
example | 例示用 | example/foo-bar |
- charsetパラメータを利用することで、メディアタイプの文字エンコーディングを指定することができる
→ application/json;charset=utf-8
- charsetパラメータは省略可能であるが、タイプが「text」の場合はデフォルト文字エンコーディングがISO8859-1と定義されているので、注意が必要(日本語を利用する際には文字化けを起こす)
- XMLのように文書全体で文字エンコーディングを表現する場合でも、textタイプの場合はContent-Typeのcharsetパラメータを優先するという仕様がある
- XML宣言の文字エンコーディング例
<?xml version="1.0" encoding="utf-8" />
■ 言語タグ
- Content-Languageヘッダで、リソース表現の自然言語を指定する
- charsetパラメータは文字エンコーディング方式を指定するものであるので、Content−Languageと区別する
- Content−Languageヘッダの値は「言語タグ」と呼ばれる文字列である
- 言語タグの「-」の左側にはISO 639が定義する言語コードが入る。言語タグの「-」の右側にはISO 3166が定義する地域コードが入る
→「ja-JP」、「en-US」など
■ コンテントネゴシエーション
- メディアタイプや文字エンコーディングや言語タグはサーバーが一方的に決定するのではなく、クライアントと交渉して決めることもできる。この手法を「コンテントネゴシエーション」と呼ぶ
- Acceptヘッダで、クライアントは自分が処理できるメディアタイプをサーバーに伝えることができる
(例) Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
- 「q=」というパラメータの値を「qvalue」と呼ぶ。これにより、メディアタイプの優先順位を指定することができる。qvalueは0〜1までの数値で、数値が大きい方を優先する。
- クライアントがAcceptヘッダで指定したメディアタイプにサーバーが対応していない場合は「406 Not Acceptable」が返る
[リクエスト] GET /test HTTP/1.1 Host: example.jp Accept: application/xml, application/msword;q=0.9 [レスポンス] HTTP/1.1 406 Not Acceptable
- Accept-Charsetヘッダで、処理できる文字エンコーディングを指定することができる
→ Accept-Charset: Shift_JIS, utf-8;q=0.7,*;q=0.7
- Accept-Languageヘッダで、処理できる言語を伝えることができる
→ Accept-Language: ja,en-us;q=0.7,en;q=0.3
■ Content-Lengthとチャンク転送
- Content-Lengthヘッダで、ボディの長さを指定することができる。10進数のバイトで示す。
→ Content-Length: 5538
- チャンク転送とはボディを分割して転送すること
- Transfer-Encodingヘッダにchunkedを指定すると、最終的なサイズがわからないボディを少しずつ転送することができる。
POST /test HTTP/1.1 Host: example.jp Transfer-Encoding: chunked Content-Type: text/plain; charset=utf-8
■ 認証
- 現在主流のHTTP認証方式には、HTTP1.1が規定しているBasic認証とDigest認証がある。またWeb APIではWSSEというHTTP認証の拡張仕様を利用する場合もある
- あるリソースにアクセス制御がかかっている場合、ステータスコード401とWWW-Authenticateヘッダを利用してクライアントにリソースへのアクセスに必要な認証情報を通知できる
[リクエスト] DELETE /tset HTTP/1.1 Host: example.jp [レスポンス] HTTP/1.1 401 Unauthorized WWW-Authenticate: Basic realm="Example.jp"
■ キャッシュ
- キャッシュとは、サーバーから取得したリソースをローカルストレージに蓄積し、再利用する手法のこと。また、ローカルストレージにキャッシュしたデータそのもののこともキャッシュと呼ぶ。
- クライアントはサーバーから取得したリソースがキャッシュ可能かどうかを調べ、可能な場合はローカルストレージに蓄積する
- リソースがキャッシュ可能かどうかは、そのリソースを取得したときのヘッダで判断される
- キャッシュのための情報を提供するヘッダには、「Pragma」と「Expires」と「Cache-Control」の3種類がある
- Pragmaヘッダで、キャッシュの抑制が可能である
- Pragmaヘッダに「no-cache」が指定されている場合、リソースをキャッシュしてはならないことを示す
HTTP/1.1 200 OK Content-Type: application/xhtml+xml; charset=utf-8 Pragma: no-cache
- Expiresヘッダでキャッシュの有効期限を示すことができる
- Expiresヘッダに示された日時を見て、クライアントは次回同じリソースにアクセスする際にキャッシュを利用するかを判断する
- Expiresヘッダには最長で約1年後の日時を入れることを仕様では推奨している
HTTP/1.1 200 OK Content-Type: application/xhtml+xml; charset=utf-8 Expires: Thu, 11 May 2010 16:00:00 GMT
- Cache-Controlヘッダで詳細なキャッシュ方法を指定することができる
- PragmaヘッダとExpiresヘッダの機能はCache−Controlで完全に代用することができる
- 「Pragme: no-cache」は「Cache-Control: no-cache」と全く同じ
- Expiresヘッダは有効期限を絶対時間で指定したが、Cache-Controlヘッダでは現在からの相対時間を指定することができる
→ Cache-Control: max-age: 86400(86400秒、すなわち24時間キャッシュが新鮮であることを意味する)
- クライアントがExpiresヘッダやCache-Controlヘッダを検証した結果、ローカルキャッシュを再利用できないと判断した場合でも、条件付きGETを利用すればキャッシュを再利用できる可能性がある
- 条件付きGETはサーバー側にあるリソースがクライアントローカルのキャッシュから変更されているかを調べるヒントをリクエストヘッダに含めることで、キャッシュがそのまま使えるかどうかを検証する仕組みである
- 条件付きGETは、そのリソースがLast-ModifiedヘッダまたはETagヘッダを持っている時に利用できる
- If-Modified-Sinceヘッダで、リソースの更新日時を条件に指定することができる
GET /test HTTP/1.1 Host: example.jp If-Modified-Since: Thu, 11 May 2010 16:00:00 GMT
- If-None-Matchヘッダで、リソースのETagを条件に指定することができる
- If-None-Matchヘッダに指定する値はキャッシュしてあるリソースのETagヘッダの値である
- If-Modified-Sinceヘッダが「指定した日時以降に更新されていれば」という条件なのに対して、If-None-Matchヘッダは「指定した値にマッチしなければ」という条件になる
- ETagはリソースの更新状態を比較するためだけに使う文字列である
GET /test HTTP/1.1 Host: example.jp If-None-Match: ab332208
■ 持続的接続
- 持続的接続は、HTTP1.1で新しく出現した機能
- HTTP1.0では接続のたびにコネクションを切断していたため、動作が重たくなっていた。この問題を解決するためにクライアントとサーバーの間でコネクションを保ち続ける持続的接続が開発された
- Keep-Aliveヘッダで、持続的接続を実現することができる。HTTP1.1ではkの持続的接続がデフォルトの動作になった
- 持続的接続ではクライアントはレスポンスを待たずに同じサーバにリクエストを送信することができる。これを「パイプライン化」と呼ぶ。
- コネクションを切断したい場合は、リクエストでConnectionヘッダにcloseという値を設定すればよい
GET /test HTTP/1.1 Host: example.jp Connection: close