コンテントネゴシエーションと 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> ディレクティブは、リクエストされたファイル名ではなくて、サーバ上の実際のファイル名を指定しなくてはいけない、ということに注意しましょう。

参考文献

Firefox で画像の下に隙間が出来てしまう問題

以下のような HTML コードを考えます。

<div style="border: solid 1px #666666;"><img alt="sample" src="XXX.png" /></div>
普通は画像と div 要素の border の間に隙間が出来ないと思いますよね? 実際 MIME タイプを "text/html" として Firefox で表示したときには隙間はできません。

しかし、何故か MIME タイプを "application/xhtml+xml" として Firefox で表示すると画像の下に隙間ができてしまいました。。 なぜ!?

ということで色々調べたのですが、なにせ "application/xhtml+xml" で web ページを提供してる人は少ないので情報が全く無く・・・、結局 レイアウトエンジンが Standards モードである際に表中の画像行間に隙間がある理由 ぐらいしか情報は見つかりませんでした。 ただ現象としては一緒だったので、同じ方法で解決しました。

個人的には画像の下には隙間が無いほうがありがたいんですが・・・仕様なんでしょうか。

その他の場合 (2009.05.26 追記)

上で書いたのは MIME タイプが "application/xhtml+xml" という特殊な状況の場合の話です。 一般的な MIME タイプ "text/html" の場合は関係ありません。

MIME タイプが "text/html" で、画像の下に隙間が空くって場合は CSS プロパティの vertical-aling 属性を疑ってみる のがいいんじゃないでしょうか。