April 23, 2003
HTML から <script language="JavaScript" type="text/javascript" src="xx.js"> なんて書いておくと、JavaScript を外部ファイルから呼び出すことが出来るっていうのはごく一般的な方法なんですが、にぽたんの会社の web サーバでは、この JavaScript ファイルは、実は実体となる js ファイルが存在せず、Apache から特定のリクエストヘッダや接続元の情報に応じて出力を分ける、独自の Apache Perl モジュールとして存在しています。
まぁ、ある意味 JavaScript を出力する CGI みたいなもんです (違うけど)。
つまり、xx.js なんて、一見するとある一個の JavaScript ファイルのようで、実は
みたいにして、Apache::NipotanJS (仮名) というモジュールから、conf/nipotan_js.dat とかを読み込んで、動的に js のデータを生成しとります。
で、他にもこのサーバには、mod_gzip とかも入っています。
この Apache::NipotanJS は、数パターンの JavaScript で、条件が一致する限りまったく同じ JavaScript が呼ばれますので、サーバ側のキャッシュを使ったりもしてるんですが、ある情報筋から、Last-Modified ヘッダや ETag ヘッダ (オプション) があれば、ブラウザはキャッシュされたファイルの元の日時や ETag の値をリクエストヘッダ (If-Modified-Since とか If-None-Match とか) に含めて、それが一致したら、304 Not Modified ステータスを返すとか…(Apache::File の meets_conditions() メソッドが行う)。
で、Last-Modified とかは、モジュールが関連するファイル全ての更新日時を元に (それらが更新されていない限りは中身は同じはず) 最新時刻を設定していました。
しかしこれを実装しているのに、何故かどうやっても IE はそんなヘッダをリクエストに含めず、常に最新の情報を求めてしまっていて、何でなのかさっぱりわからずじまい。
わからずじまいの状態で約半月過ごしました。
しかーし!今日その原因がわかりました。
それが、mod_gzip と密接に関係していたなんて、全然気付かなかったです。
js ファイルが、gzip 圧縮されていると、Mozilla とか Netscape 系のブラウザがエラーになるので、httpd.conf にて、
にして、Content-Type: application/x-javascript を吐き出す Apache::NipotanJS の出力データは、非圧縮にして送っていました。
ところがどっこい、その後か前かに mod_gzip を通過するときに、mod_gzip が Vary: Accept-Encoding を付加するだけ (かな?) して、当然クライアントには非圧縮データが送られるんですが、IE が Accept-Encoding を含めているのに、非圧縮データを出力するコンテンツにこの Vary: Accept-Encoding ヘッダがあると、常に最新のデータを拾いにいくっぽいです。
なので、Apache のログにも、304 ステータスが異常に少ないなーと思っていたのですが、Apache::NipotanJS の handler() メソッドに
を含めただけ (ホントはもっとごちゃごちゃやってるけど) で、完全にキャッシュと比較するようになりました。
いやー、わかりづらいですね。IE は。
Mozilla & Netscape 系ブラウザは、ちゃんとキャッシュと比較してるんですよ。
ブラウザによってこうも動作が違うと、それに対応する側はつくづく大変です。
発見ポイントは、アクセスログの mod_gzip のステータスで、IE の中でも NO_ACCEPT_ENCODING だったブラウザのみがキャッシュとの比較をして 304 ステータスを受け取っていたので、ふと気付きました。
で、いざリリースしてログを tail -f で流していると…
ちゃんと 304 ステータスバリバリ流しています。負荷軽減です。いやー、(・∀・)イイ!!!
昨日は散々な一日でしたが、今日はこんな発見があって、チョットうれすぃい一日でした。
相変わらずのヲタネタすまそ。
まぁ、ある意味 JavaScript を出力する CGI みたいなもんです (違うけど)。
つまり、xx.js なんて、一見するとある一個の JavaScript ファイルのようで、実は
<Location /xx.js>
SetHandler perl-script
PerlHandler Apache::NipotanJS
PerlSetVar JSSettings conf/nipotan_js.dat
</Location>
みたいにして、Apache::NipotanJS (仮名) というモジュールから、conf/nipotan_js.dat とかを読み込んで、動的に js のデータを生成しとります。
で、他にもこのサーバには、mod_gzip とかも入っています。
この Apache::NipotanJS は、数パターンの JavaScript で、条件が一致する限りまったく同じ JavaScript が呼ばれますので、サーバ側のキャッシュを使ったりもしてるんですが、ある情報筋から、Last-Modified ヘッダや ETag ヘッダ (オプション) があれば、ブラウザはキャッシュされたファイルの元の日時や ETag の値をリクエストヘッダ (If-Modified-Since とか If-None-Match とか) に含めて、それが一致したら、304 Not Modified ステータスを返すとか…(Apache::File の meets_conditions() メソッドが行う)。
で、Last-Modified とかは、モジュールが関連するファイル全ての更新日時を元に (それらが更新されていない限りは中身は同じはず) 最新時刻を設定していました。
しかしこれを実装しているのに、何故かどうやっても IE はそんなヘッダをリクエストに含めず、常に最新の情報を求めてしまっていて、何でなのかさっぱりわからずじまい。
わからずじまいの状態で約半月過ごしました。
しかーし!今日その原因がわかりました。
それが、mod_gzip と密接に関係していたなんて、全然気付かなかったです。
js ファイルが、gzip 圧縮されていると、Mozilla とか Netscape 系のブラウザがエラーになるので、httpd.conf にて、
mod_gzip_item_exclude mime ^application/.*
にして、Content-Type: application/x-javascript を吐き出す Apache::NipotanJS の出力データは、非圧縮にして送っていました。
ところがどっこい、その後か前かに mod_gzip を通過するときに、mod_gzip が Vary: Accept-Encoding を付加するだけ (かな?) して、当然クライアントには非圧縮データが送られるんですが、IE が Accept-Encoding を含めているのに、非圧縮データを出力するコンテンツにこの Vary: Accept-Encoding ヘッダがあると、常に最新のデータを拾いにいくっぽいです。
なので、Apache のログにも、304 ステータスが異常に少ないなーと思っていたのですが、Apache::NipotanJS の handler() メソッドに
my $headers = $r->headers_out();
delete $headers->{Vary};
を含めただけ (ホントはもっとごちゃごちゃやってるけど) で、完全にキャッシュと比較するようになりました。
いやー、わかりづらいですね。IE は。
Mozilla & Netscape 系ブラウザは、ちゃんとキャッシュと比較してるんですよ。
ブラウザによってこうも動作が違うと、それに対応する側はつくづく大変です。
発見ポイントは、アクセスログの mod_gzip のステータスで、IE の中でも NO_ACCEPT_ENCODING だったブラウザのみがキャッシュとの比較をして 304 ステータスを受け取っていたので、ふと気付きました。
で、いざリリースしてログを tail -f で流していると…
ちゃんと 304 ステータスバリバリ流しています。負荷軽減です。いやー、(・∀・)イイ!!!
昨日は散々な一日でしたが、今日はこんな発見があって、チョットうれすぃい一日でした。
相変わらずのヲタネタすまそ。