http-header

メッセージのボディに対する付加情報の表現 HTTPヘッダ

前回は、レスポンスメッセージの意味を伝える数字であるステータスコードについてまとめた。ここでは、メッセージのボディに対する付加情報の表現であるHTTPヘッダについて説明する。

1 HTTPヘッダの重要性

ヘッダ(header)は、メッセージのボディに対する付加的な情報(メタデータ)を表現する。クライアントやサーバは、ヘッダを見てメッセージに対する挙動を決定する。また、リソースへのアクセス権を設定する認証や、クライアントとサーバの通信回数と量を減らすキャッシュなどのHTTPの機能を実現する。このように、ヘッダはメソッドやステータスコードと並んでHTTPの重要な構成要素である。

 

2 HTTPヘッダの生い立ち

TCP/IPをベースとしたプロトコル HTTPの基本8項でも述べたように、HTTPの最初のバージョン0.9にはヘッダがなかった。HTTPで転送する本文のメタデータを表現するために、電子メールのメッセージ仕様(RFC822)のヘッダ形式を借りてくる形で追加された。そのため、HTTPヘッダと電子メールのメッセージヘッダは共通部分がある。例えば、Message-IdヘッダやSubjectヘッダはメールでしか利用しないが、Content-TypeヘッダやDateヘッダはHTTPでも利用する。

HTTPと電子メールプロトコルには違いもある。最も大きな違いは、メールプロトコルが一方向(One-Way)にしかメッセージをやりとりしないのに対し、HTTPは一度の通信でリクエスト/レスポンスの2つのメッセージをやりとりする点である。そのため、HTTPでは電子メールにはない、様々なヘッダを追加している。

 

3 日時

まず、値に日時を持つヘッダである。DateやExpiresが相当し、以下の6つが挙げられる。HTTPでは電子メールに合わせた日時のフォーマットを利用する。

  • Date:メッセージを生成した日時
  • If-Modified-Since:条件付きGETでリソースの更新日時を指定するときに利用する
  • If-Unmodified-Since:条件付きPUTや条件付きDELETEでリソースの更新日時を指定するときに利用する
  • Expires:レスポンスをキャッシュできる期限
  • Last-Modified:リソースを最後に更新した日時
  • Retry-After:再度リクエストを送信できるようになる日時の目安

 

4 MIMEメディアタイプ

MIME(Multipurpose Internet Mail Extensions)メディアタイプとは、メッセージでやりとりするリソースの表現の種類を指定するものである。電子メールのMIMEは複数のメールヘッダを定義する仕様だが、HTTPではそのうちのContent-Typeヘッダなどいくつ化を利用する。

 

Content-Type—メディアタイプを指定する

Content-Typeヘッダは、そのメッセージのボディの内容がどのような種類なのかをメディアタイプで示す。XHTML(Extensible Hypertext Markup Language)を表すメディアタイプ(application/xhtml+xml)においては、「/」の左側をタイプ(Type)、右側をサブタイプ(Subtype)と呼ぶ。

タイプは勝手に増やすことはできない。現状ではRFC2045(メッセージフォーマット)とRFC2046(メディアタイプ)で、以下の9つを定義している。サブタイプは比較的自由に増やすことができる。登録済みのタイプとサブタイプの一覧はIANAが管理している。

  • text:人が読んで直接理解できるテキスト
  • image:画像データ
  • audio:音声データ
  • video:映像データ
  • application:その他のデータ
  • multipart:複数のデータからなる複合データ
  • message:電子メールメッセージ
  • model:複数次元で構成するモデルデータ
  • example:例示用

 

charsetパラメーター文字エンコーディングを指定する

charsetパラメータとは、文字エンコーディングを指定することである。これは省略可能だが、タイプがtextの場合は注意が必要である。HTTPでは、textタイプのデフォルト文字エンコーディングはISO8859-1と定義しているため、文字化けを引き起こす可能性がある。そのため、textタイプの場合は必ずcharsetパラメータを付けるようにすれば解決できる。さらに、XML文書の場合はtext/xmlを使わずに、application/xmlやapplication/xhtml+xmlのようなメディアタイプを利用することが望ましい。

 

5 言語タグ

言語タグ(Language Tag)と呼ばれる文字列は、リソース表現の自然言語を指定するContent-Languageヘッダの値である。これは、RFC4646(言語タグ)とRFC4647(言語タグの比較方法)が定義している。

 

6 コンテントネゴシエーション

コンテントネゴシエーション(Content Negotiation)とは、メディアタイプや文字エンコーディング、言語タグにおいて、サーバが一方的に決定するだけではなく、クライアントと交渉して決める方法である。

 

Accept—処理できるメディアタイプを伝える

Acceptヘッダは、クライアントが自分の処理できるメディアタイプをサーバに伝える場合に利用する。

 

Accept-Charset—処理できる文字エンコーディングを伝える

Accept-Charsetヘッダは、クライアントが自分の処理できる文字エンコーディングをサーバに伝える場合に利用する。

 

Accept-Language—処理できる言語を伝える

Accept-Languageヘッダは、クライアントが自分の処理できる言語タグをサーバに伝える場合に利用する。

 

7 Content-Lengthとチャンク転送

Content-Length—ボディの長さを指定する

Content-Lengthヘッダは、メッセージが持つボディのサイズを10進数のバイトで示す。

 

チャンク転送—ボディを分割して転送する

チャンク転送とは、Transfer-Encodingヘッダにchunkedを指定して、ボディを分割して転送する方法である。例えば、動的に画像生成するようなWebサービスにおいて、ファイルサイズが決まるまでレスポンスを返せないという問題を解決するために用いる。

 

8 認証

現在主流のHTTP認証方式には、HTTP1.1が規定しているBasic認証とDigest認証がある。また、Web APIではWSSE(WS-Security Extension)というHTTP認証の拡張仕様を利用する場合もある。

あるリソースにアクセス制御がかかっている場合、ステータスコード401 Unauthorized(このリソースのアクセスには適切な認証が必要)とWWW-Authenticateヘッダを利用して、クライアントにリソースへのアクセスに必要な認証情報を通知できる。

 

Basic認証

Basic認証はユーザ名とパスワードによる認証方式である。ユーザ名とパスワードはAuthorizationヘッダに入れてリクエストごとに送信する。Authorizationヘッダの内容は、認証方式(Basic)に続けて、ユーザ名とパスワードを「:」で連結しBase64エンコードした文字列になる。注意点は、Base64エンコーディングは簡単にデコード(復号)可能なことである。

 

Digest認証

Digest認証とは、Basic認証より安全な認証方式で、チャレンジとダイジェストの生成と送信という流れで行われる。

 

チャレンジ

チャレンジ(Challenge)とは、nonce、qop、opaqueの3つを含むWWW-Authenticateヘッダの値のことである。nonce(number used once)とは、リクエストごとに変化する文字列で、生成するハッシュ値をより安全にする目的で利用する。qop(quality of protection)とは、保証の品質と訳され「auth」か「auth-init」を指定する。opaqueとは、クライアントには不透明な(推測できない)文字列で、同じURI空間へのリクエストでは共通してクライアントからサーバに送る。

 

ダイジェストの生成と送信

サーバから認証に必要な情報を得たクライアントは、自分のユーザ名とパスワードを使ってダイジェストを生成する。そして、その値をresponseというフィールドに入れて、リクエストを送信する。

 

Digest認証の利点と欠点

Digest認証の利点は、パスワードを盗まれる危険性がないことと、パスワードそのものをサーバに預けなくてもいいことである。欠点は、メッセージ自体は平文でネットワーク上を流れること、クライアント側の操作が煩雑なこと、ホスティングサービスではサポートしていない可能性があることである。

 

WSSE認証

WSSE(WS-Security Extension)認証はHTTP 1.1の標準外の認証方法である。Atom PubなどのWeb APIの認証に使われている。WS-SecurityのUsernameTokenという認証方式を基に策定され、Basic認証やDigest認証も使えない場合に用いられる。WSSE認証は、パスワードをネットワーク上に流さなくていい一方、サーバ側ではパスワードを保存しておく必要があるなど、Basic認証とDigest認証の中間に位置する認証方式といえる。

 

9 キャッシュ

キャッシュ(Cache)とは、サーバから取得したリソースをローカルストレージ(ハードディスクなど)に蓄積し、再利用する手法のことである。クライアントが蓄積したキャッシュは、そのキャッシュが有効な間、クライアントが再度そのリソースにアクセスしようとしたときに再利用する。

 

キャッシュ用ヘッダ

キャッシュ用ヘッダには、以下の3つのヘッダがある。Pragmaヘッダはキャッシュを抑制するものである。Expiresヘッダはキャッシュの有効期限を示すものである。Cache-Controlは詳細なキャッシュ方法を指定するものである。これらの3つのヘッダを使い分ける方針は、以下の3つである。

  • キャッシュをさせない場合は、PragmaとCache-Controlのno-cacheを同時に指定する
  • キャッシュの有効期限が明確に決まっている場合は、Expiresを指定する
  • キャッシュの有効期限を相対的に指定したい場合は、Cache-Controlのmax-ageで相対時間を指定する

 

条件付きGET

条件付きGETとは、サーバ側にあるリソースが、クライアントローカルのキャッシュから変更されているかどうかを調べるヒントをリクエストヘッダに含めることで、キャッシュがそのまま使えるかどうかを検証するしくみである。リソースがLast-ModifiedヘッダまたはETagヘッダを持っているときに利用できる。

条件付きGETには以下の2つの手法がある。If-Modified-Sinceヘッダはリソースの更新日時を条件にするものである。If-None-MatchヘッダはリソースのETagを条件にするものである。この2つのヘッダの使い分けは、ETagヘッダがなくLast-Modifiedヘッダしかわからない場合は、If-Modified-Sinceヘッダを使う。クライアントの立場で、サーバがETagを出している場合はIf-None-Matchヘッダを利用する方がいい。

 

10 持続的接続

持続的接続(Persistent Connection)とは、クライアントとサーバの間でリクエストの度に切断することなく、まとめて接続し続ける手法である。HTTP 1.1での大きな新機能で、デフォルトの動作である。持続的接続では、クライアントはレスポンスを待たずに同じサーバにリクエストを送信でき(パイプライン化(Pipelining))、より効率的にメッセージを処理できる。

 

11 その他のHTTPヘッダ

HTTP標準ではないが、よく使われているヘッダについて以下にまとめる。

 

Content-Disposition—ファイル名を指定する

Content-Dispositionヘッダとは、サーバがクライアントに対してそのリソースのファイル名を提示するために利用するレスポンスヘッダである。

 

Slug—ファイル名のヒントを指定する

Slugヘッダとは、AtomPub(RFC5023)が追加した拡張HTTPヘッダであり、クライアントがAtomのエントリをPOSTする際に、新しく生成するリソースのURIのヒントとなる文字列をサーバに提示できるものである。

 

12 HTTPヘッダを活用するために

HTTPヘッダの特徴は、電子メールや言語タグ、文字エンコーディングなど、他の標準を積極的に活用していることである。そのため、HTTPヘッダをうまく使うためには、これらの歴史と実際のサーバやブラウザの実装を調査する能力が必要となる。

 

最後に

ヘッダはメソッドやステータスコードと組み合わせて、認証やキャッシュなどのHTTPの重要な機能を実現する。また、メディアタイプや言語タグなど、フレームワークではなく実装者が具体的に設定しなければならないヘッダも多くある。このように、HTTPヘッダを使いこなすためには、多様な知識やノウハウを学ぶ必要がある。

次回は、タグで文書の相互リンク構造を表現するコンピュータ言語であるHTMLについてまとめる。

Webを支える技術 -HTTP、URI、HTML、そしてREST (WEB DB PRESS plus)


コメントを残す

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です

次のHTML タグと属性が使えます: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>