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

このページの目次

概要

この文書では,HTTP/1.1で新しく導入されたコンテントネゴシエーションという機構についてと,Apacheでコンテントネゴシエーションを実現するための手順について解説しています。

コンテントネゴシエーションとは

HTTP/1.1では,リクエストに応じてサーバで適切なリソースを選んで出力するコンテントネゴシエーションcontent negotiation)という仕組みが導入されました。ここではサーバ駆動型コンテントネゴシエーションについて解説します。

あるリソースは,様々な形態で存在できる場合があります。例えば,HTML文書は,日本語だけでなく,英語やフランス語の文書も同時に提供できるかもしれません。また,画像は,png形式だけではなく,jpeg形式やgif形式でも提供できるかも知れません。コンテントネゴシエーションとは,あらかじめ複数のリソースをサーバに用意しておき,ユーザからのリクエストに応じて適切なリソースを自動的に選び,出力する仕組みのことです。

具体例を見てみましょう。ユーザがサーバにリクエストするとき,HTTPヘッダというものを出力するのですが,例えば私の使っているMozillaでは,http://www.example.com/foo/barにアクセスするときは次のような行が出力されます(一部省略)。

GET /foo/bar HTTP/1.1
Host: www.example.com
User-Agent: Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.5) Gecko/20031007
Accept: text/xml,application/xml,application/xhtml+xml,text/html;q=0.9,text/plain;q=0.8,image/png,image/jpeg,image/gif;q=0.2,*/*;q=0.1
Accept-Language: ja,en-us;q=0.7,en;q=0.3
Accept-Encoding: gzip,deflate
Accept-Charset: Shift_JIS,utf-8;q=0.7,*;q=0.7

この中で,User-AgentからAccept-Charsetまでのどの行もコンテントネゴシエーションに関係しうるのですが,ここではAcceptフィールド・Accept-Languageフィールド・Accept-Charsetフィールドに関して説明します。

Accept-Languageフィールド

順番を変えてまずはAccept-Languageフィールドから。

Accept-Language: ja,en-us;q=0.7,en;q=0.3

Accept-Languageフィールドは,「どの言語のファイルが欲しいよ」という要求を表すためのフィールドです。要求に優先度の順番を付けるために,品質値quality values)という値を用います。品質値は1が最高で0が最低です。つまり,品質値が1のものは最も欲しい種類のリソースで,品質値が0のものは要らない種類のリソースであるということになります。先のリクエストは,次のような要求を表しています。

  1. 一番欲しいのは日本語(ja)のリソースです(品質値1)。

  2. 次に欲しいのはアメリカ英語(en-us)のリソースです(品質値0.7)。

  3. その次に欲しいのは英語(en)のリソースです(品質値0.3)。

サーバは,この要求を見て,複数の種類のリソースから適切なリソースを選んでユーザに送ります。もし,要求にかなうリソースが存在しない場合(例えば,フランス語の文書しか用意されていない場合),サーバは300 Multiple Choicesか406 Not Acceptableを返して,「私のサーバにはこれこれこういった種類のリソースしかないんですよ」というのを提示できます。

Accept-Charsetフィールド

Accept-Charsetフィールドは,受け入れられる文字コードの種類を提示します。

Accept-Charset: Shift_JIS,utf-8;q=0.7,*;q=0.7

*は「何でも良い」ということを表します。ですから,これは,次のような要求を表します。

  1. 一番欲しいのは,文字コードがシフトJIS(Shift_JIS)のリソースです(品質値1)。

  2. 次に欲しいのは,文字コードがUTF-8(utf-8)のリソースか,あるいは文字コードがその他全て(*)のリソースです(品質値0.7)。

Acceptフィールド

Acceptフィールドは,欲しいリソースの種類(メディアタイプ)を表します。

Accept: text/xml,application/xml,application/xhtml+xml,text/html;q=0.9,text/plain;q=0.8,image/png,image/jpeg,image/gif;q=0.2,*/*;q=0.1

少々長いですが,これは次のような要求を表します。

  1. 一番欲しいのは,XML文書(text/xmlapplication/xml)か,XHTML文書(application/xhtml+xml)か,PNG画像(image/png)か,JPEG画像(image/jpeg)です(品質値1)。

  2. 次に欲しいのは,HTML文書(text/html)です(品質値0.9)。

  3. その次に欲しいのは,テキスト文書(text/plain)です(品質値0.8)。

  4. その次に欲しいのは,GIF画像(image/gif)です(品質値0.2)。

  5. その次に欲しいのは,その他何でも(*/*)です(品質値0.1)。

以上で説明したようなリクエストによって,サーバに対してどんなリソースが欲しいのかを伝えることができ,サーバはその要求に応じて適切なリソースを選んでユーザに送ることができます。この仕組みが(サーバ駆動型)コンテントネゴシエーションです。ヘッダフィールドの詳しい文法についてはRFC2616を参照してください。

Apacheでの設定の仕方

コンテントネゴシエーションを行うためには,サーバ側でも設定をしておく必要があります。現在最も一般的となっているApache HTTPサーバにおける設定の仕方を紹介します。

.htaccessファイル

初めに断っておきますが,サーバ管理者が設定の上書きを許可していない場合下記の設定は効果がありません。.htaccessファイルが使えるかどうか,Optionsディレクティブの上書きが許可されているかどうかをあらかじめ確認しておいてください(セキュリティ上の問題により,使用不可としているサーバが多いようです)。

まず,コンテントネゴシエーションを行いたいディレクトリに,次の内容の.htaccessというファイル名のファイルを作ります。行末には必ず改行を入れてください

Options +MultiViews
Note

Windowsは,一瞬ピリオドで始まるファイル名のファイルは作れないように見えるけれど,何故かコマンドプロンプトからなら作れたりするという謎の仕様になっています。まぁ,ローカルでは仮のファイル名にしておいて,サーバに送ってからリネームするという方法でも全然OKです。

サーバに送信するときは,必ずテキストモードで送ってください。

用意するファイル

Apacheでは,メディアタイプ・言語・文字コードについては拡張子で指定します。例えば,次のようなものがデフォルトで定義されています(httpd.confとmime.typesを参照)。

拡張子とメディアタイプ・言語・文字コードの対応
拡張子メディアタイプ・言語・文字コード
.html.htmHTML文書(text/html
.xhtml.xhtXHTML文書(application/xhtml+xml
.pngPNG画像(image/png
.jpeg.jpg.jpeJPEG画像(image/jpeg
.ja日本語(ja
.en英語(en
.utf8UTF-8
Note

サーバ管理者がこの設定を上書きして変更している可能性があるので注意してください(おそらくデフォルトのままがほとんどだとは思いますけど)。

文字コードのデフォルト設定に日本語でよく使われる文字コードが含まれていませんが,.htaccessを使えばメディアタイプ・言語・文字コードの拡張子のマッピングを変更することができます。詳細は後述します(拡張子のマッピングの追加・上書き)。

拡張子の順番は基本的に関係ありません。例えば,foo.html.ja.utf8としても,foo.ja.utf8.htmlとしても基本的に同じです(ただし,途中まで拡張子を省略する形でのアクセスで違いが生じます)。

アクセスするときは拡張子を省略したファイル名でアクセスします。foo.html.ja.utf8とfoo.xhtml.ja.utf8とfoo.html.en.utf8とfoo.xhtml.en.utf8というファイルを用意していた場合,「foo」というファイル名でアクセスすると,これら4つのファイルの中からリクエストに応じて適切なファイルが選択され,ユーザに送られます。拡張子は必ずしも全部省略する必要はなく,「foo.html」でもアクセスできます(この場合はfoo.html.ja.utf8とfoo.html.en.utf8の2つのファイルから適切なファイルが選択されます)。当然,全く省略しない形の「foo.html.ja.utf8」でもアクセスできます。ただし,「foo.ja」ではアクセスできません(foo.jaで始まるファイルが存在しないため)。

拡張子のマッピングの追加・上書き

文字コードのデフォルト設定に日本語でよく使われる文字コードが含まれていませんが,.htaccessを使えばメディアタイプ・言語・文字コードの拡張子のマッピングを変更することができます。メディアタイプの拡張子マッピングを追加・上書きするにはAddTypeディレクティブ,言語の拡張子マッピングを追加・上書きするにはAddLanguageディレクティブ,文字コードのマッピングを追加・上書きするにはAddCharsetディレクティブを使います。記述の仕方は次のようになります。どのような順番で記述しても構いません。

AddLanguage ja-Osaka .osaka
AddCharset EUC-JP .euc
AddCharset ISO-2022-JP .jis
AddCharset SHIFT_JIS .sjis
AddType application/octet-stream .gca
Note

ISO-2022-JPというのはいわゆるJISコードのことです。

Note

日本語の言語コードはjaであり,日本の国コードはJPです。言語コードにJPを使うことはできませんので注意してください。

コンテントネゴシエーションのメリット・デメリット

メリット

  • コンテントネゴシエーションを利用すると,ユーザに適した形式のファイルを自動的に選択して送信することができます。

  • URIの永続性が保証されます。例えば,将来,HTMLが使われなくなって,UTML(Ultratext Markup Language)なる新しいマークアップ言語による記述が一般的になったとしても,.htmlから.utmlへとURIを変更する必要はありません。ただ,UTML形式のファイルを新しく追加するだけで,URIを変更しなくともUTMLに対応することができるのです。さらに,旧形式であるHTML形式での提供も同時に続けることができます。

    参考

デメリット

  • まだあまり広く使われている技術ではありません。ユーザは拡張子なしのファイルにアクセスするのに対して違和感を持っている可能性があります。

  • メンテナンスコストがかかります。つまり,1つのリソースに対してファイルを複数形式用意するのは(自動化する仕組みを用意しなければ)大変です。

    ただし,必ずしも複数形式のファイルを用意する必要はありません。ファイルを1つしか用意しなくても,URIの永続性を維持するためには十分であると考えられます。

  • .htaccessの使用が許可されているサーバはあまり多くありません。導入したくてもできないケースが多いでしょう。

  • URIだけを見て,それがあらかじめどんな種類のファイルであるかを推測できません。あるリソースはHTML文書かもしれないし,PNG画像かもしれないし,PDF文書かもしれないのです。これを不便に感じる人がいるかもしれません。

  • 現在最も普及しているブラウザであるIEのリクエストがいまいちです。というのも,奴は未だにHTTP/1.0を使い続けてるのです(HTTP/1.1は4年以上前に発表されたんだけどなぁ……)。HTTP/1.0は,AcceptフィールドやAccept-Charsetフィールド・Accept-Languageフィールドがおまけ程度の規定しかされておらず,品質値の規定は存在しませんでした。IEは一応AcceptフィールドやAccept-Languageフィールドは出力するようですが(Accept-Charsetフィールドは出力しないようです),Acceptフィールドも,HTTP/1.1の立場から見るとやや残念な感じになっています。

    修正(2004-02-12) : IEがHTTP/1.0を使い続けているというのは誤りでした。ローカルプロキシをかましてリクエストをチェックしていたんですが,「プロキシ接続の時はHTTP/1.0を使う」という設定になっていたため,HTTP/1.0しか使えないものと誤解していました。インターネットオプションよりHTTP/1.1を使うかどうかを設定できるようになっています。しかし,HTTP/1.1を使う設定にしても,リクエストの最初の1行が変わるだけで,他のリクエストラインは全く変わらない様子。AcceptフィールドとAccept-Languageフィールドはやっぱり残念な感じです。

  • 1つのリソースに対していくつものファイルを用意する必要があるので,サーバ容量を食います。

コンテントネゴシエーションを勧めるためにこの文書を書いたのに,どうもデメリットばかり思いつくなぁ……。