コンテンツキャッシュとVaryヘッダとnginx

  • 87
    いいね
  • 0
    コメント
この記事は最終更新日から1年以上が経過しています。

この記事はnginx Advent Calendar 2015の3日目の記事です。

コンテンツキャッシュ

HTTP通信時にクライアント/サーバ間にキャッシュサーバが存在する場合、キャッシュサーバは特定のヘッダの内容ごとにキャッシュを分けるといった工夫が必要になることがあります。

クライアント <-> キャッシュサーバ <-> サーバ

例えばクライアントがAccept-Encoding: gzip, deflate付きのリクエストを送ってきた場合、サーバはgzip圧縮したコンテンツを返すことができます。さらに前段のキャッシュサーバはそのレスポンスをキャッシュすることができます。

しかし、すべてのクライアントがAccept-Encoding: xxx付きのリクエストを送ってくるとは限りません。この場合、サーバは素のコンテンツをレスポンスとして返します。また、前段のキャッシュサーバはこのレスポンスもキャッシュすることができます。

さて、ここで問題が生じます。キャッシュサーバは圧縮済みのコンテンツをキャッシュすべきでしょうか?それとも圧縮していないコンテンツをキャッシュすべきでしょうか?

この問題はVaryヘッダを利用することで解決できます。

Varyヘッダ

Varyヘッダは前段のキャッシュサーバに対して、指定したヘッダの内容ごとにキャッシュを分ける必要があることを伝えるためのものです。例えばサーバがVary: Accept-Encodingをレスポンスヘッダに付加しておくと、キャッシュサーバはAccept-Encodingヘッダの内容に応じたキャッシュを保持します。

Vary: Accept-Encoding

こうすることでクライアントのAccept-Encodingヘッダの内容に応じたキャッシュデータをキャッシュサーバは返すことができるというわけです。

nginxにおけるgzip圧縮とVaryヘッダ

さて、本題です。上記のような事情からかApacheのmod_deflateh2oなんかはコンテンツのgzip圧縮を有効にすると、自動的にVary: Accept-Encodingをレスポンスヘッダに付加します。一方我らがnginxは設定ファイルにgzip_vary on;と書かないとVary: Accept-Encodingをレスポンスヘッダに付加しません

非常に重要なことなのでもう一度言うと、nginxは設定ファイルにgzip_vary on;と書かないとVary: Accept-Encodingをレスポンスヘッダに付加しません

gzip_vary on;

nginxの前段にキャッシュサーバやCDNが配置されている際はこの事実を頭に入れておくとよいでしょう。

(おまけ)nginxとViaヘッダ

ヘッダの内容ごとにキャッシュを分ける件はこれでよいとして、nginxの前段にキャッシュサーバやCDNがあるともうひとつめんどくさいのがあります。Viaヘッダです。

Viaヘッダはクライアント/サーバ間にあるキャッシュサーバやCDNが、「自分のサーバをプロキシとして経由したよー」と明示するために付けるヘッダです。例えばCloudfrontなんかを通るとこのヘッダが付いてきます。そしてnginxは受け取ったリクエストにViaヘッダが含まれていると設定ファイルにgzip on;と書いてもレスポンスをgzip圧縮しません

非常に重要なことなのでもう一度言うと、nginxは受け取ったリクエストにViaヘッダが含まれていると設定ファイルにgzip on;と書いてもレスポンスをgzip圧縮しません

Viaヘッダが付いててもレスポンスをgzip圧縮したい場合はgzip_proxiedディレクティブを利用します。

gzip_proxied any;

これでViaヘッダ付きのリクエストに対してもgzip圧縮したレスポンスを返すことができます。めでたしめでたし。