Landscape トップページ | < 前の日 2005-09-13 2005-09-14 次の日 2005-09-15 >

Landscape - エンジニアのメモ 2005-09-14

Content Negotiation でリクエストに応じて gzip 圧縮ファイルを返す


* Content Negotiation でリクエストに応じて gzip 圧縮ファイルを返す

この記事の直リンクURL: Permlink | この記事が属するカテゴリ: [Apache] [http]

HTTP の Content Negotiation 機能を使うと、ユーザの環境に応じて適切なファイルを返すことができる。

これを利用すると、以下を実現できる。
HTTP リクエストヘッダ Accept-Encoding: gzip を送ってきているクライアントにはあらかじめ gzip で圧縮しておいたファイルを返し、Accept-Encoding: gzip を送ってきていないクライアントには gzip 圧縮していない生のファイルを返す。

- Content Negotiation を利用して圧縮ファイルを返す手法と mod_gzip/mod_deflate の違い

クライアントが送ってくるリクエストヘッダに応じて、圧縮したデータまたは生のデータを返す。一見 mod_gzip や mod_deflate がやっていることと同じように見えるが、違う。最大の違いは動的にファイルを圧縮するのではなく、最初から圧縮済みのファイルを置いておくことにある。

動的に生成するページを圧縮したいなら、mod_gzip や mod_deflate のフィルタを使うのがよいだろう。しかし、静的ページならば、あらかじめ圧縮したファイルを返す方式でも良い。毎回圧縮をしないので、CPU 資源を節約することにもつながる。

また、mod_gzip や mod_deflate が使えないサーバでも圧縮を利用できるというメリットがある。現在 sonic64.com はさくらインターネットのホスティングサービスを利用している。残念なことに私の利用しているコースでは mod_gzip が使えない。Content Negotiation 以外の方法でコンテンツを圧縮して返そうと思ったら、すべてを CGI にしてコード中で圧縮するか、proxy を挟むくらいしか方法がない。

- Apache で Content Negotiation

Apache だと MultiViews を使う。

コンテントネゴシエーション - Apache HTTP サーバ
http://httpd.apache.org/docs/2.1/content-negotiation.html
Multiviews

MultiViews はディレクトリ毎のオプションで、 httpd.confファイルの <Directory>, <Location>, <Files> セクション中や、(AllowOverride が適切な値に 設定されていると) .htaccess ファイルで Options ディレクティブによって設定することができます。 Options All は MultiViews をセットしないことに注意してください。明示的に その名前を書く必要があります。

MultiViews が有効になると、クライアントのリクエストに応じてサーバが最適なファイルを選択して返すようになる。
私の使っているサーバは httpd.conf で MuitiViews が有効になっているようなので試してみる。

まず、生のファイルと、圧縮して拡張子 .gz を付加したファイルを用意する。

[21:27:32][hiroaki@sonic64 ~/public_html/test]$ ls -l
-rw----r--  1 hiroaki  users  39751 Sep 13 21:18 cl.xml
-rw----r--  1 hiroaki  users  9785 Sep 13 21:18 cl.xml.gz

ブラウザからリクエスト。

http://sonic64.com/test/cl.xml

GET /test/cl.xml HTTP/1.1
Host: sonic64.com
User-Agent: Mozilla/5.0 (Windows; U; Windows NT 5.1; ja-JP; rv:1.7.10) Gecko/20050717 Firefox/1.0.6
Accept: text/xml, application/xml,application/xhtml+xml, text/html;q=0.9,text/plain;q=0.8, image/png,*/*;q=0.5
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
Keep-Alive: 300
Connection: keep-alive
Pragma: no-cache
Cache-Control: no-cache

HTTP/1.x 200 OK
Date: Tue, 13 Sep 2005 12:29:40 GMT
Server: Apache/1.3.33 (Unix)
Last-Modified: Tue, 13 Sep 2005 12:18:00 GMT
Etag: "3449c4-9b47-4326c378"
Accept-Ranges: bytes
Content-Length: 39751
Keep-Alive: timeout=3, max=8
Connection: Keep-Alive
Content-Type: application/xml

あれ? うまく Content-Negotiation されてないな。なんで? リクエストするファイル名を変えてみるか。cl.xml じゃなくて、cl をリクエストしてみよう。

http://sonic64.com/test/cl

GET /test/cl HTTP/1.1
Host: sonic64.com
User-Agent: Mozilla/5.0 (Windows; U; Windows NT 5.1; ja-JP; rv:1.7.10) Gecko/20050717 Firefox/1.0.6
Accept: text/xml, application/xml,application/xhtml+xml, text/html;q=0.9,text/plain;q=0.8, image/png,*/*;q=0.5
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
Keep-Alive: 300
Connection: keep-alive
Pragma: no-cache
Cache-Control: no-cache

HTTP/1.x 200 OK
Date: Tue, 13 Sep 2005 12:35:24 GMT
Server: Apache/1.3.33 (Unix)
Content-Location: cl.xml.gz
Vary: negotiate,accept-encoding
TCN: choice
Last-Modified: Tue, 13 Sep 2005 12:18:02 GMT
Etag: "3449c8-2639-4326c37a;4326c74b"
Accept-Ranges: bytes
Content-Length: 9785
Keep-Alive: timeout=3, max=8
Connection: Keep-Alive
Content-Type: application/xml
Content-Encoding: gzip

今度はうまくいった。Content-Location: cl.xml.gz と Vary: negotiate,accept-encoding が返されている。cl でリクエストすると Content-Negotiation が働き、cl.xml でリクエストしたときは Content-Negotiation がなされない。なんでだろう?

コンテントネゴシエーション - Apache HTTP サーバ
http://httpd.apache.org/docs/2.1/ja/content-negotiation.html
リンクに MIME タイプを使い続けたい (例えば foo.html)時は、言語拡張子は (エンコーディング拡張子もあればそれも含めて) MIME タイプ拡張子の右側になければなりません (例えば foo.html.en)。

上記ページの説明を見る限り、foo.MIME-TYPE.ENCODING のファイルは foo.MIME-TYPE でアクセスできるはずなんだけどなあ。 とりあえずなんで cl でないとダメなのかは後で調べてみよう。

- mod_mime が 拡張子 gz のファイルを Content-Encoding: gzip にしている

うまく Content-Negotiation がなされて gz ファイルが返されたとき、Content-Encoding: gzip も同時にサーバから返されていて、いわゆる「透過的な圧縮」になっている。mod_gzip や mod_deflate を使ったときと同じような、HTTP 転送データそのものを圧縮している状態だ。

これはとくに Content-Negtiation とは関係ない。以下のように、cl.xml.gz を直接リクエストしたときも Content-Encoding: gzip がサーバから返されている。

http://sonic64.com/test/cl.xml.gz

GET /test/cl.xml.gz HTTP/1.1
Host: sonic64.com
User-Agent: Mozilla/5.0 (Windows; U; Windows NT 5.1; ja-JP; rv:1.7.10) Gecko/20050717 Firefox/1.0.6
Accept: text/xml, application/xml,application/xhtml+xml, text/html;q=0.9,text/plain;q=0.8, image/png,*/*;q=0.5
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
Keep-Alive: 300
Connection: keep-alive

HTTP/1.x 200 OK
Date: Tue, 13 Sep 2005 12:42:35 GMT
Server: Apache/1.3.33 (Unix)
Last-Modified: Tue, 13 Sep 2005 12:18:02 GMT
Etag: "3449c8-2639-4326c37a"
Accept-Ranges: bytes
Content-Length: 9785
Keep-Alive: timeout=3, max=8
Connection: Keep-Alive
Content-Type: application/xml
Content-Encoding: gzip

Content-Encoding: gzip を返しているのは mod_mime だ。Apache のデフォルトでこの機能が働くように httpd.conf が記述されている。httpd.conf の以下の部分が該当箇所。もし設定されていなければ、.htaccess で設定する。

<IfModule mod_mime.c>

    #
    # AddEncoding allows you to have certain browsers (Mosaic/X 2.1+) uncompress
    # information on the fly. Note: Not all browsers support this.
    # Despite the name similarity, the following Add* directives have nothing
    # to do with the FancyIndexing customization directives above.
    #
    AddEncoding x-compress Z
    AddEncoding x-gzip gz tgz

ん? 今気づいたけど、拡張子 tgz も AddEncodding してるの? それだと tgz という拡張子を付けたファイルの場合、クライアント側で gzip を展開してしまうので gzip されたファイルを保存したいとユーザが考えたときなどに問題になるんじゃないのかな? Google で AddEncoding x-gzip gz tgz を検索するとヒット。

Re: .tar.gz -> .tgz
http://search.fml.org/mlarchives/fml-help/200107/msg397.html
gz が展開されてしまう、という問題ですよね?

あ、やっぱり。.tar.gz という拡張子なら Content-Encoding が付かないので問題ないが、.tgz にすると Content-Encoding が付いてしまうので展開さてしまうと。まあ tgz なんて拡張子を使わないようにするか、AddEncoding から tgz を消せば良いだけだから実害は少ないかな。

- cl.xml へのリクエストを cl.xml.gz にネゴシエーションしたい

うーん、なんだか今日はやりたいことができなかったなあ。

cl.xml にリクエストがあったとき、Accept-Encoding に gzip があり、かつ cl.xml.gz がサーバに存在していたら Content-Encoding: gzip で cl.xml.gz の中身を返すようにしたいだけなんだけどなあ。cl.xml を CGI にでもすれば簡単にできるけど、それじゃあサーバに余計な負荷をかけてしまう。しょうがない、mod_rewrite を使うか。明日やってみよう。

すべての記事の見出し (全1029件)
全カテゴリの一覧と記事の数
カテゴリごとに記事をまとめ読みできます。記事の表題だけを見たい場合は、すべての記事の見出し (カテゴリ別表示) へ。

直近30日分の記事
2007-04-23 (Mon)
2007-03-07 (Wed)
2007-02-27 (Tue)
2007-01-17 (Wed)
2007-01-15 (Mon)
2007-01-14 (Sun)
2007-01-08 (Mon)
2006-12-01 (Fri)
2006-11-22 (Wed)
2006-11-20 (Mon)
2006-11-19 (Sun)
2006-09-30 (Sat)
2006-08-29 (Tue)
2006-08-04 (Fri)
2006-07-27 (Thu)
2006-07-23 (Sun)
2006-07-17 (Mon)
2006-07-10 (Mon)
2006-07-06 (Thu)
2006-07-03 (Mon)
2006-06-29 (Thu)
2006-06-28 (Wed)
2006-06-27 (Tue)
2006-06-25 (Sun)
2006-06-19 (Mon)
2006-06-18 (Sun)
2006-06-15 (Thu)
2006-06-11 (Sun)
2006-06-01 (Thu)
2006-05-30 (Tue)
プロファイル
斎藤 宏明。エンジニアです。宇都宮市に住んでいます。
リンク
RSS
スポンサードリンク
Powered by
さくらインターネット

© 斎藤 宏明 Saito Hiroaki Gmail Address
Landscape - エンジニアのメモ http://sonic64.com/
Landscape はランドスケープと読みます。
ひらがなだと らんどすけーぷ です。