コンテントネゴシエーションと Vary レスポンスヘッダ

うちのサイト (vivid code) は XHTMLMIME タイプを "application/xhtml+xml" で配信しています。 ただ、IE ではそれを閲覧できないという問題があります。 そこでうちのサイトでは HTTP リクエストヘッダを見て、Accept フィールドに "application/xhtml+xml" が含まれて居ない場合は MIME タイプを "text/html" に変換するという処理を施しています。

で、自宅から見ている分にはちゃんと Firefox 等では "application/xhtml+xml" で見れて、IE では "text/html" になっている、というのを確認できていたのですが、何故か大学のネットワーク内から閲覧すると IE で見ても "application/xhtml+xml" のままになっていることがあって、ずーっと悩んでいました。

が、本日 水無月ばけらのえび日記さんとこの記事 を見て疑問解決。


正しく Vary: を出力していないと、間にキャッシュサーバを挟んでいる場合などに不具合が起きる可能性があります。
おそらく大学内にはキャッシュサーバがあって・・・うちのサイトのあるページを (大学内から) Firefox で見るとキャッシュサーバに MIME タイプ "application/xhtml+xml" としてキャッシュされてしまう、と。 その後で同じページに IE でアクセスすると、キャッシュサーバにキャッシュされているものをダウンロードするので MIME タイプが "appilcation/xhtml+xml" になってしまう、というわけです。 多分。

で、その場合の解決策として HTTP レスポンスヘッダの Vary フィールドをちゃんと設定してやる必要があるようです。

HTTP レスポンスヘッダの Vary フィールド

HTTP レスポンスヘッダの Vary フィールドってなんぞ? ということですが、HTTP ヘッダ一覧 によると

言語、文字コードなど複数の表現形式が許されている場合のネゴシエーションで、サーバがどれを選択したか通知
するもののようです。 例えば、HTTP リクエストヘッダの Accept フィールドの値によってサーバが返すコンテンツを変える場合は、Vary フィールドの値を "Accept" にすべき、というわけです。 うちのサイトの場合は、リクエストヘッダの Accept フィールドに "application/xhtml+xml" が含まれているかどうかによって、サーバが送出するコンテンツを変化させているので、Vary フィールドの値を "Accept" にすべきなんですね。

HTTP レスポンスヘッダと <FilesMatch> ディレクティブ

というわけで、早速 htaccess ファイルを弄ってレスポンスヘッダの Vary を設定しようとしたのですが・・・なぜか <FilesMatch> ディレクティブが上手く動かないという罠に引っかかってしまいました。

まさに以下の状況。

うちの場合は
<FilesMatch "\.xhtml$">
Header set Vary "Accept"
</FilesMatch>
こんな感じに書いたのですが、うまく動きませんでした。 けど
<FilesMatch ".*">
Header set Vary "Accept"
</FilesMatch>
とするとちゃんと Vary フィールドが設定されていたので、<FilesMatch> ディレクティブの中で Header set が使えない、なんてことはないようです。 単に、FilesMatch "\.xhtml$" が何故か ***.xhtml ファイルにマッチしないというだけで。 なんで? 謎過ぎるんですが・・・。 未解決なんで解決策がわかる方は教えてください・・・。

とりあえずはファイル名によらずに Vary フィールドを設定するようにしましたが・・・。

解決 【追記】

<FilesMatch> ディレクティブが期待通りの動作をしないという問題が解決しました。

うちのサイトでは XHTML ファイルにアクセスされたときに、リクエストヘッダの Accept フィールドに "application/xhtml+xml" が無ければ translater.cgi (XHTML ファイルを "text/html" に書き換えるための CGI) が処理を行って、その結果をブラウザに返すようにしてあるわけで、んじゃ当然 <FilesMatch> ディレクティブでも拡張子 xhtml のファイルだけじゃなくて translater.cgi にもマッチするようにしなくちゃダメじゃーん、というわけなのでした。 勘違いしてスミマセン。

<FilesMatch> ディレクティブや <Files> ディレクティブは、リクエストされたファイル名ではなくて、サーバ上の実際のファイル名を指定しなくてはいけない、ということに注意しましょう。

参考文献