gzip圧縮転送についてトコトン調べてみた

  • 公開日:
gzip

この記事の目次

はじめに

Webページのパフォーマンスを測定する「PageSpeed Insights」は、パフォーマンスを改善するための提案をしてくれます。その提案の一つに「圧縮を有効にする」があり、次のように述べられています。

多くのウェブサーバーでは、(中略)ファイルをダウンロード用に送信する前にgzip形式で圧縮できます。圧縮すると、ウェブサイトを表示するのに必要なリソースのダウンロードにかかる時間を削減できます。

今回は、パフォーマンス向上のためのgzip圧縮転送について取り上げます。

gzipとは何か

gzipとは「RFC 1952に記述されているファイル圧縮プログラムgzipによって作られるエンコーディングフォーマット」のことです。

gzip圧縮の対象となるのは、HTML、CSS、JavaScriptなどのテキスト形式のファイルです。一方で、圧縮してはいけないファイルもあります。

画像やPDFファイルは既に圧縮がかかっていますので、圧縮してはいけません。圧縮しようとすればCPUパワーを無駄遣いするばかりでなく、ファイルサイズが増えてしまう可能性があります。

出典:Steve Souders『ハイパフォーマンスWebサイト ― 高速サイトを実現する14のルール

gzip圧縮の方法

gzip圧縮転送をおこなうには、次の2つの方法があります。

1. サーバーでgzip圧縮する

Apacheの場合、.htaccessを書き換えてmod_deflateモジュールを用いれば、サーバーがgzip圧縮してくれます。ただし、HTTPリクエストがあるごとにサーバーがgzip圧縮をおこなうため、サーバーの負荷につながります。

2. gzip圧縮したファイルをサーバーに用意する

あらかじめサーバーにgzip圧縮したファイルを用意する方法もあります。上記の方法ではgzip圧縮によってサーバーに負荷がかかりますが、それを回避することができます。

gzipの作り方はいくつかありますが、編集するたびにgzip圧縮するのは面倒なのでタスクランナーでgzip化する方法をオススメします。私はgulpを使っているので、gulp-gzipでgzip圧縮を自動化しています。

gzip圧縮転送をおこなう.htaccessの書き方

上記の「2. gzip圧縮したファイルをサーバーに用意する」の方法でgzip圧縮転送をおこなう場合、.htaccessファイルは以下のように記述します。

RewriteEngine on
RewriteCond %{HTTP:Accept-Encoding} gzip
RewriteCond %{REQUEST_FILENAME}\.gz -s
RewriteRule ^(.+) $1.gz

<FilesMatch "\.css\.gz$">
  ForceType text/css
  AddEncoding x-gzip .gz
</FilesMatch>
<FilesMatch "\.js\.gz$">
  ForceType application/x-javascript
  AddEncoding x-gzip .gz
</FilesMatch>

Header append Vary Accept-Encoding env=!dont-vary

この.htaccessファイルに記述されている内容を順を追って説明していきます。

2行目

HTTPリクエストのAccept-Encodingにgzipが含まれているかを確認します。

Accept-Encodingは、ブラウザが処理できるコンテンツコーディングを伝えるために使用されます。つまり、2行目ではブラウザがgzipを処理できるかを確かめています。

ChromeのHTTPリクエスト

3行目

ファイル名に拡張子.gzがついたファイルがサーバー上に存在するかを確認します。

4行目

2行目・3行目の条件を満たした場合、リクエストURIの末尾に拡張子.gzを付け加えます。

7行目/11行目

gzip圧縮したファイルをHTTPレスポンスとして送信すると、Content-Typeapplication/gzipになってしまいます。これではブラウザがContent-Typeを正しく認識できなくなります。

そのような状況を回避するためにForceTypeを使って、CSSの場合にはContent-Typetext/css、JavaScriptの場合にはapplication/javascriptとなるようにします。

8行目/12行目

HTTPレスポンスのContent-Encodingにgzipを指定し、拡張子.gzを含むファイル名がgzip圧縮されていることを伝えます。

15行目

HTTPレスポンスのヘッダーにVary Accept-Encodingを追加します。詳しくは、次の「プロキシサーバーのキャッシュ」で説明します。

プロキシサーバーのキャッシュ

プロキシサーバーとは

プロキシサーバーとは、内部ネットワークとインターネットとの境界に置かれ、内部ネットワークの「代理(proxy)」としてインターネットに接続するサーバーのことです。

プロキシサーバーの大きな役割として、キャッシュ機能があります。一度アクセスしたWebサイトのデータをキャッシュとして残しておくことで、アクセスの高速化を図ることができます。

キャッシュによって起こる問題

最初にgzipに対応していないブラウザが、プロキシサーバーを経由して、Webサーバーにアクセスします。Webサーバーからのレスポンスは非圧縮で、プロキシサーバーには非圧縮のファイルがキャッシュされます。

次にgzipに対応しているブラウザが先ほどと同じWebサーバーにアクセスしようとすると、プロキシサーバーはキャッシュにある非圧縮のファイルをブラウザに転送します。

この場合、Webサーバーに圧縮済みのファイルがあるにもかかわらず、gzipに対応しているブラウザはgzip圧縮転送によるパフォーマンスの向上を享受できなくなってしまいます。

今度は、最初にgzipに対応しているブラウザが、プロキシサーバーを経由して、Webサーバーにアクセスする場合を考えます。Webサーバーからのレスポンスはgzip圧縮済みで、プロキシサーバーに圧縮済みのファイルがキャッシュされます。

次にgzipに対応していないブラウザが同じWebサーバーにアクセスしようとすると、プロキシサーバーはキャッシュにある圧縮済みのファイルをブラウザに転送します。

この場合、gzipに対応していないブラウザにgzip圧縮されたファイルが送信されるため、ブラウザは受信したファイルを処理できなくなります。

proxy2

問題の解決方法

上記の問題を解決するためには、WebサーバーからのレスポンスにVaryヘッダーを追加します。具体的には、.htaccessに以下の記述を加えます。

Header append Vary Accept-Encoding env=!dont-vary

こうすることで、プロキシサーバーが同じ値のAccept-Encodingを保持している場合のみにキャッシュを利用し、それ以外の場合はWebサーバーにファイルを取得しにいくようになります。

参考資料

参考サイト

参考文献