2013-03-04

CloudFlareでキャッシュ可否の条件は「URLの末尾がキャッシュ対象拡張子に見えること」だった

【この記事の概要】

この記事を3行でまとめると、
  • CloudFlareでエッジサーバーがキャッシュしてくれるかどうかは、
  • URLの末尾が「キャッシュ対象の拡張子」に見えるか否かで決まる
  • (MIMEタイプは関係ない)

では、以下、本文です。

そもそもCloudFlareって?

CloudFlareは、無料でも転送量無制限で利用できるリバースプロキシ型サービスです。

Webサイトを運営する上で、「転送量」はなかなか頭の痛い問題です。
安いレンタルサーバーだと、ちょっとアクセスが増えるとすぐアクセス量制限に引っかかって“503 Service Temporarily Unavailable”が表示されがち。
“Bandwidth: Unlimited”をうたう海外レンタルサーバーを頑張って英語で契約してみたら、「転送量は無制限だがセッション数の上限を超えた」という理由でアカウントをsuspendされて、凍結解除の交渉を英語でするハメに陥ったり……。

そんな中で、無料プランでも転送量制限のないCloudFlareは、実にありがたい存在です。
以前はエッジサーバーが日本国内になかったので「CloudFlareを使うとサイトが遅くなる」という問題もありましたが、今では日本にもエッジサーバーが設置されたようで、pingを打つと最速で5msなんて数字を叩き出したりします。

CloudFlareはどういう動作をするの?

CloudFlareはリバースプロキシとして動作します。
つまり、対象WebサーバーへのすべてのアクセスはCloudFlareのエッジサーバーを経由します。
ユーザー →①→
←④←
CloudFlare
エッジ
サーバー
→②→
←③←
ウチの
Web
サーバー

その際、特定のファイルをエッジサーバーにキャッシュしてもらうことができます。
キャッシュされたファイルは、アクセスがエッジサーバーで折り返すようになります。
ユーザー →①→
←②←
CloudFlare
エッジ
サーバー
   
ウチの
Web
サーバー
こちらのWebサーバーまでアクセスが来ないので、転送量などの資源を節約できるというわけです。

CloudFlareがキャッシュするファイルとは?

CloudFlareがどんなファイルをキャッシュしてくれるのかと言うと、具体的にはFAQ(What file extensions does CloudFlare cache for static content?)に列挙されています。
ざっくり説明すると、以下のような拡張子を持つファイルです。
  • .css
  • .js
  • .jpg/gif/png/ico/svgなどの画像ファイル
  • .pdf/csv/doc/ppt/xlsxなどのドキュメントファイル
  • .swf
  • .midi/mid
  • .pls(プレイリストファイル)

逆に言うと、リストに含まれない次のようなファイルはキャッシュされません。
  • .html/xhtml
  • .cgi/php
  • .xml
  • .json
  • .zip/bz2/rar
  • .mp3/mp4/flv
  • その他、リストに記述されていない拡張子のファイルすべて

(これらのファイルもキャッシュしてもらう方法もあるのですが、それは次回)

キャッシュ可否を決めるのはMIMEタイプ? 拡張子?

拡張子.jsはキャッシュされて、拡張子.cgiはキャッシュされない――となると気になるのが「JavaScriptを出力するCGI」はキャッシュされるのか、それともされないのか。
そこで実験してみました。

用意したのは、下記のようなJSを出力するCGIファイル。
#!/usr/bin/ruby
puts "Content-type:application/javascript"
puts
puts "document.writeln('#{Time.now.to_s}');"

これをCloudFlare経由で、以下のURLでアクセスしてキャッシュされるかどうか見てみました。

js.cgi×キャッシュされない
js.cgi/pathinfo.js○キャッシュされる
js.cgi?query=.js○キャッシュされる

MIMEタイプだけではダメで、PATH_INFOでもQUERY_STRINGでもいいからURLの末尾が対象拡張子で終わっている必要があるようです。

【確認内容】(レスポンスヘッダは一部省略)
キャッシュされる場合:
$ curl -i 'http://cloudflare.example.jp/js.cgi/pathinfo.js'
HTTP/1.1 200 OK
Server: cloudflare-nginx
Date: Mon, 04 Mar 2013 00:00:00 GMT
Content-Type: application/javascript
CF-Cache-Status: MISS
Expires: Mon, 04 Mar 2013 02:00:00 GMT

document.writeln('Mon Mar 04 09:00:00 +0900 2013');
※↑1回目のアクセス:まだキャッシュがなかった(この内容でキャッシュが作られる)

$ curl -i 'http://cloudflare.example.jp/js.cgi/pathinfo.js'
HTTP/1.1 200 OK
Server: cloudflare-nginx
Date: Mon, 04 Mar 2013 00:00:12 GMT
Content-Type: application/javascript
CF-Cache-Status: HIT
Expires: Mon, 04 Mar 2013 02:00:12 GMT

document.writeln('Mon Mar 04 09:00:00 +0900 2013');
※↑2回目のアクセス:キャッシュが使われている

キャッシュされない場合:
$ curl -i 'http://cloudflare.example.jp/js.cgi'
HTTP/1.1 200 OK
Server: cloudflare-nginx
Date: Mon, 04 Mar 2013 00:00:30 GMT
Content-Type: application/javascript

document.writeln('Mon Mar 04 09:00:30 +0900 2013');
※↑1回目のアクセス:CF-Cache-Statusヘッダがない

$ curl -i 'http://cloudflare.example.jp/js.cgi'
HTTP/1.1 200 OK
Server: cloudflare-nginx
Date: Mon, 04 Mar 2013 00:00:42 GMT
Content-Type: application/javascript

document.writeln('Mon Mar 04 09:00:42 +0900 2013');
※↑2回目のアクセスでもキャッシュされていない

ちなみに、CGIのレベルでExpiresレスポンスヘッダをわざわざ吐いても、結果は変わりませんでした。

クエリ文字列の末尾が拡張子っぽく見えること

「クエリ文字列が拡張子っぽい場合」の挙動をもう少し掘り下げてみます。

1) js.cgi?1=query&2=.js○キャッシュされる
2) js.cgi?1=.js&2=query×キャッシュされない
3) js.cgi?1=query&2=js×キャッシュされない

1)のように、URLの末尾がキャッシュ対象拡張子であれば、クエリが複数あってもキャッシュされます。

ただし、2)のように、クエリの順番を入れ替えるとキャッシュされなくなります。
3)は1)のクエリの「.js」を「js」に置き換えた(ピリオドを削った)ものですが、これもキャッシュされません。

どうやら「URLの末尾が拡張子に見える」という形式を必ず守らなければならないようです。

次回

CloudFlareの3種類のキャッシュレベルの違いを調べた
CloudFlareのキャッシュレベルは Basic / Simplified / Aggressive の3段階から選べますが、その違いについて調べます。

0 件のコメント:

コメントを投稿