Apache のコンテントネゴシエーションのサポートは HTTP/1.1 の規格に合うように 更新されました。それにより、ブラウザにより提供されたメディアタイプ、 言語、キャラクタセットと、エンコーディングの優先順位を用いてリソースの 一番良い表現方法を選択できます。また、不完全なネゴシエーション用の情報を 送ってくるブラウザからのリクエストをより優雅に扱うための機能を いくつか実装しています。
コンテントネゴシエーションは mod_negotiation モジュールにより 提供されていて、デフォルトで組み込まれています。
リソースは、幾つか異なった表現で利用できる場合があります。 たとえば、異なる言語や異なるメディアタイプ、またはそれらの組み合わせで 利用できるかも知れません。もっとも適した選択をする方法の一つには、 インデックスページをユーザに見せて、ユーザに選んでもらう方法があります。 しかし、サーバが自動的に選ぶことができる場合が多くあります。 これは、ブラウザがリクエスト情報毎の情報の一部に、 どの表現を嗜好するかを送ることで動作しています。 たとえばブラウザは、可能ならフランス語で情報を見たい、 不可能ならその代わりに英語でもよいと、自分の嗜好を知らせることができます。 ブラウザはリクエストのヘッダで自分の優先傾向を知らせます。 フランス語の表現だけを要求する場合は、ブラウザは以下を送ります。
Accept-Language: fr
この優先傾向は、選択可能な表現が存在して、 言語によって様々な表現がある場合にのみ適用される ということに注意してください。
もっと複雑なリクエストの例を挙げましょう。 このブラウザはフランス語と英語を受け付ける、 しかしフランス語を好む、そして様々なメディアタイプを受け付けるが、 プレインテキストや他のタイプよりは HTML を好む、 他のメディアタイプよりは GIF や JPEG を好む、しかし最終手段として 他のメディアタイプも受け付ける、というように設定されています。
Accept-Language: fr; q=1.0, en; q=0.5 Accept: text/html; q=1.0, text/*; q=0.8, image/gif; q=0.6, image/jpeg; q=0.6, image/*; q=0.5, */*; q=0.1
Apache 1.2 は HTTP/1.1 の規格で定義されている 'server driven' コンテントネゴシエーションをサポートしています。 Accept, Accept-Language, Accept-Charset, Accept-Encoding リクエストヘッダを完全にサポートしています。Apache 1.3.4 は RFC 2295 と RFC 2296 で定義されている実験的なネゴシエーションプロトコルである、 'transparent' もサポートしています。それらの RFC で定義されている 'feature negotiation' はサポートしていません。
リソースとは URI で特定される概念上のもののことです (RFC 2396)。 Apache のような HTTP サーバは、その名前空間の中での リソースの表現へのアクセスを提供します。 それぞれの表現は定義されたメディアタイプ、文字セット、 エンコーディング等の付属した、バイト列の形式です。 それぞれのリソースはある時点で 0 個、1 個、それ以上の表現と 関連付けられる可能性があります。複数の表現が利用できる場合は、 リソースはネゴシエーション可能であるとされ、 個々の表現は variant と呼ばれます。 ネゴシエーション可能なリソースの variant が異なる、その状態を指して、 ネゴシエーションの次元と呼びます。
リソースをネゴシエーションするためには、サーバはそれぞれの variant についての情報を知っておく必要があります。 これは以下の二つの方法のどちらかで行われます。
*.var
ファイル)
を使う方法。これは、variant
を明示的に挙げているファイルを指定します。タイプマップは type-map
ハンドラ (もしくは、古い
Apache の設定に上位互換となるために維持されている mime タイプ
application/x-type-map
)
に関連付けられたドキュメントです。
この機能を使うためには、あるファイルの拡張子を
type-map
として定義するハンドラを設定ファイルで設定する
必要があることに注意してください。これは
AddHandler type-map .var
をサーバの設定に書くことが一番良い方法です。 詳細はサンプルの設定ファイルのコメントを参照してください。
タイプマップファイルにはそれぞれの variant
についてのエントリがあります。これらのエントリは連続した HTTP
のヘッダ行から成ります。別の variant のエントリとは空行で
分けられています。エントリ中に空行があってはいけません。
マップファイルは全体のエンティティをくっつけた形で始めるのが
習慣となっています
(これは要求されているわけではなく、もしあった場合は無視されます)。
たとえば、マップファイルは次のようになります。この例では、
ファイルの名前は foo.var
で、リソース foo
のいろいろな variant があるディレクトリに配置されることになります。
URI: foo URI: foo.en.html Content-type: text/html Content-language: en URI: foo.fr.de.html Content-type: text/html;charset=iso-8859-2 Content-language: fr, de
variant の品質が違うときは、この画像のように (JPEG, GIF, ASCII アートがあります) メディアタイプの "qs" パラメータとして指定されます。
URI: foo URI: foo.jpeg Content-type: image/jpeg; qs=0.8 URI: foo.gif Content-type: image/gif; qs=0.5 URI: foo.txt Content-type: text/plain; qs=0.01
qs 値の範囲は 0.000 から 1.000 です。qs 値が 0.000 の variant は決して選択されないことに注意してください。'qs' 値のない variant は qs 値 1.0 を 与えられます。qs パラメータはクライアントの能力に関係無く、他の variant と比較したときの variant の相対的な「品質」を示します。たとえば、 写真を表現しようとしているときは JPEG ファイルの方が普通は ASCII ファイルよりも高い品質になります。 しかし、リソースが元々 ASCII アートで表現されているときは、ascii ファイルの方が JPEG ファイルよりも高い品質になります。このように、qs は表現されるリソースの性質によって variant 毎に特有の値を取ります。
認識されるヘッダの完全な一覧は以下のようになります:
URI:
Content-Type:
image/gif
, text/plain
,
text/html; level=3
です。Content-Language:
en
、 韓国語は kr
,
等)。Content-Encoding:
x-compress
や
gzip されたファイルのための x-gzip
のようなエンコーディングを含みます。
エンコーディングの比較時には接頭辞 x-
は無視されます。Content-Length:
Description:
MultiViews
はディレクトリ毎のオプションで、
<Directory>
, <Location>
,
<Files>
や、(AllowOverride
が適切な値に設定されていると) .htaccess
ファイルで Options
ディレクティブによって設定することができます。Options
All
は MultiViews
を設定しないことに注意してください。
明示的にその名前を書く必要があります。
MultiViews
の効果は以下のようになります:
サーバが /some/dir/foo
へのリクエストを受け取り、
/some/dir/foo
が存在しない場合、
サーバはディレクトリを読んで、foo.*
にあてはまるすべてのファイルを探し、
事実上それらのファイルをマップするタイプマップを作ります。
そのとき、メディアタイプとコンテントエンコーディングは、
そのファイル名を直接指定したときと同じものが割り当てられます。
それからクライアントの要求にもっとも合うものを選び、
そのドキュメントを返します。
サーバがディレクトリの索引を作ろうとしていると、
MultiViews
は DirectoryIndex
ディレクティブで指定された名前の探索にも適用されます。
設定ファイルに
DirectoryIndex index
が書かれていて、index.html
と
index.html3
が両方存在していると、
サーバはその中から毎回どちらかを適当に選びます。
もしその両方が存在せずに index.cgi
が存在していると、サーバはそれを実行します。
ディレクトリを読んでいるときに見つかったファイルに CGI スクリプトがあった場合は、何が起こるべきかは自明ではありません。 そのような場合はコードは特別な扱いをしています。リクエストが POST か QUERY_ARGS や PATH_INFO のある GET の場合は、スクリプトに非常に高い品質が与えられ、 通常それが起動されます。その他のリクエストのときは、スクリプトには 非常に低い品質が与えられ、他のものが(もしあれば)取得されます。
Apache がタイプマップファイルかディレクトリのファイル名から リソースの variant の一覧を取得したら、「最善」の variant を選ぶために 二つの方法のどちらかを起動します。Apache のコンテントネゴシエーションの機能を使うために、 どのようにネゴシエーションが行なわれるかの詳細を知る必要は ありません。 しかし、これ以降では関心のある人のためにその方法を説明します。
ネゴシエーション方法は二つあります。
Dimension | Notes |
---|---|
メディアタイプ | Accept ヘッダフィールドでブラウザにより示される。 それぞれの項目は品質係数を持つことが出来ます。 variant の説明にも品質係数 ("qs" 要素)を持つことができます |
言語 | Accept-Language ヘッダフィールドでブラウザにより示される。 それぞれの項目は品質係数を持つことが出来ます。 variants は 0, 1, またはそれ以上の言語と関連づけることができます。 |
エンコーディング | Accept-Encoding ヘッダフィールドでブラウザにより示される。 それぞれの項目は品質係数を持つことが出来ます。 |
キャラクタセット | Accept-Charset ヘッダフィールドでブラウザにより示される。 それぞれの項目は品質係数を持つことが出来ます。Variants でもメディアタイプの要素としてキャラクタセットを示すことが出来ます。 |
ブラウザに返す「最適な」variant を(もしあれば)選択するように Apache は次のアルゴリズムを使うことができます。このアルゴリズムは 未だ設定可能なものではありません。次のように動作します:
LanguagePriority
ディレクティブの言語順で最適な言語の variant を選びます。
text/*
メディアタイプであるけれども
特定の文字セットに明示的に関連づけられているわけではない
variant は ISO-8859-1 であると仮定されます。ここに来たということは、variant が一つも選択されなかった (ブラウザが許容するものがなかったため) ということです。406 ステータス ("No Acceptable representation" を意味する) が、利用可能な variant のリストのついた HTML ドキュメントとともに返されます。 変化の次元を示す HTTP Vary ヘッダも設定されます。
Apacheにより返されるエラーメッセージが必要以上に簡明で、 (同等の内容を提示しているけれども、) ユーザが混乱する原因になることに留意すべきです。 もしユーザがこのエラーページを見ることを避けたい場合は、 標準の言語の(また、標準のエンコーディング等を添えた) 文書を置いておくことで、もしブラウザから要求された言語や エンコーディング等が使えなかった場合は常にそれが返されます。
ブラウザから要求された言語の文書がどれも得られない時に デフォルト言語の文書を返したい場合は、 言語属性セットなしの文書を作成してください。詳細は後の Variants with no Language 参照。
上記の Apache ネゴシエーションアルゴリズムの厳格な解釈で得られるであろう値から、 Apache は品質数値を時々変えます。完全ではない、 あるいは正確でない情報を送るブラウザ向けのアルゴリズムで、 よりよい結果を得るために行われます。かなりポピュラーなブラウザで、 もしないと間違った variant を選択する結果になってしまうような Accept ヘッダ情報を送るものもあります。 ブラウザが完全で正しい情報を送っていれば、 この数値変化は適用されません。
Accept: リクエストヘッダはメディアタイプの優先傾向を指定します。 これはまた、"image/*" や "*/*" といった「ワイルドカード」メディアタイプを含むことができます。 ここで * は任意の文字列にマッチします。ですから、次の:
Accept: image/*, */*を含むリクエストは、"image/" ではじまるタイプすべてが許容できる、 そして他のどんなタイプも許容できる (この場合はじめの "image/*" は冗長になります) ことを示します。 扱うことのできる明示的なタイプに加えて、 ルーチンのようにワイルドカードを送るブラウザもあります。たとえば:
Accept: text/html, text/plain, image/gif, image/jpeg, */*こうすることの狙いは、明示的にリストしているタイプが優先されるけれども、 異なる表現が利用可能であればそれでも良い、ということです。 しかしながら基本的なアルゴリズムでは、上に示したように、*/* ワイルドカードが他のすべてのタイプと全く同等なので優先されません。 ブラウザは */* にもっと低い品質 (優先) 値を付けてリクエストを送るべきなのです。たとえば:
Accept: text/html, text/plain, image/gif, image/jpeg, */*; q=0.01明示的なタイプには品質数値が付けられていませんので、デフォルトの 1.0 (最高値) の優先になります。ワイルドカード */* は低い優先度 0.01 を与えられているので、明示的にリストされているタイプに合致する variant がない場合にのみ、他のタイプが返されます。
もし Accept: ヘッダが q 値を全く含んでいなければ、 望みの挙動をするために、Apache は "*/*" があれば 0.01 の q 値を設定します。また、"type/*" の形のワイルドカードには 0.02 の q 値を設定します (ですからこれらは "*/*" のマッチよりも優先されます)。 もし Accept: ヘッダ中のメディアタイプのどれかが q 値を含んでいれば、 これらの特殊な値は適用されず、正しい情報を送るブラウザからの リクエストは期待通りに動作しはじめます。
もし特定のリソースの variant のうちのいくつかが言語属性を持っていて いくつかは持っていない場合は、それらの言語属性を持たない variant には 0.001 という非常に低い品質係数が与えられます
この言語属性を持たない variant に 0.001 という非常に低い品質係数が与えられるという設定の理由は ブラウザの言語設定に合う variant が一つもなかったときに標準の variant を適用することを可能にするためです。これにより、 リクエストされたリソースに対して、用意していない言語だけを accept するように設定されたブラウザのユーザが "406" エラーページを見るのを避けることが可能になります。
たとえば Multiviews が有効で variants が三つある状況を考えます。
言語属性のない variant の意味は常にブラウザに適応することです。
リクエストが foo
で Accept-Language ヘッダに en
または fr (またはその両方) が含まれる場合、foo.en.html か
foo.fr.html のどちらかが返されます。ブラウザが許容するものとして
en と fr のどちらも挙げられていない場合は代わりに foo.html
が返されます。クライアントが foo.html
をリクエストした場合は完全に一致するのでネゴシエーションは発生せず、
それ自体が返されます。この問題を避けるには、「言語のない」 variant
として foo.html.html
という名前を付けることが Multiviews
そして言語ネゴシエーションが動作するための保険として
役立つことが時々あります。
{encoding ..}
要素を variant リスト中に使うことができます。
リスト中のエンコードされた variant を認識できて、Accept-Encoding
リクエストヘッダに従って許容されるエンコードをもった variant
は、どれでも候補 variant として使用できるようにするために、
RVSA/1.0 アルゴリズム (RFC 2296) の実装が拡張されました。
RVSA/1.0 の実装では、最適な variant が見つかるまで、
計算した品質数値は小数点以下 5 桁まで丸めません。
言語ネゴシエーションを使っている場合は、ファイルが一つ以上の拡張子を持てて、 拡張子の順番には関連性が通常はない (詳細は mod_mime を参照) ので、幾つかの異なる名前の変換を選べることになります。
典型的なファイルでは、MIME タイプ拡張子 (たとえば html) を持っていて、エンコーディング拡張子 (たとえば gz) を持っているかもしれないし、 このファイルに異なる言語 variant を用意していれば、もちろん言語拡張子 (たとえば en) を持っているでしょう。
例:
正しいリンク、不正なリンクの両方のファイル名の例を挙げます:
ファイル名 | 正解のリンク | 不正解のリンク |
---|---|---|
foo.html.en | foo foo.html |
- |
foo.en.html | foo | foo.html |
foo.html.en.gz | foo foo.html |
foo.gz foo.html.gz |
foo.en.html.gz | foo | foo.html foo.html.gz foo.gz |
foo.gz.html.en | foo foo.gz foo.gz.html |
foo.html |
foo.html.gz.en | foo foo.html foo.html.gz |
foo.gz |
上の表を見て、拡張子なしのリンク (たとえば foo) がいつでも使えることに気が付くでしょう。この利点は、 ドキュメントとして応答するファイルの実際のファイルタイプを隠蔽して、 リンクの参照を変更することなく後からファイルを変更できる、 たとえば html から shtml に、あるいは cgi に変更できる点です。
リンクに MIME タイプを使い続けたい (たとえば foo.html)時は、言語拡張子は (エンコーディング拡張子もあればそれも含めて) MIME タイプ拡張子の右側になければなりません (たとえば foo.html.en)。
キャッシュがある表現を保存しているときは、リクエスト URL と関連づけられています。次にその URL がリクエストされた時に、 キャッシュは保存されている表現を使用できます。しかし、リソースが サーバでネゴシエーション可能であれば、最初のリクエストでキャッシュされて続く キャッシュヒットでは間違った応答を返してしまうということになりかねません。 これを防ぐために、Apache はコンテントネゴシエーションの 後に返された応答すべてに、HTTP/1.0 クライアントでの non-cacheable とマークします。また、ネゴシエーションされた応答のキャッシュ を可能にする HTTP/1.1 プロトコルの機能も Apache はサポートします。
HTTP/1.0 準拠のクライアントからのリクエストに対しては、
(ブラウザであろうとキャッシュであろうと) ネゴシエーション
を受けた応答のキャッシュを許すために、CacheNegotiatedDocs
ディレクティブを使用できます。このディレクティブは、
主サーバ設定やバーチャルホストで与えられて、引数をとりません。
HTTP/1.1 クライアントからのリクエストには効力を持ちません。