REST 制約の Cacheability

キャッシュはクライアントとサーバの通信回数の削減や通信量の節約のために使用する。
例えば今見ているこのページをリロードしたときのステータスを開発ツールで確認してもらうと 304 Not Modified が表示されると思うので見てもらいたい。
これは表示に使われたデータがリロード時に取得されたものではなく、ウェブブウラウザに保存されたキャッシュデータが再利用されたことを表していて、通信量の節約が行われていることが確認できる。

まずは、サーバからクライアントにリソースをキャッシュさせる方法と、キャッシュさせない方法について述べる。

キャッシュさせる

サーバからクライアントにリソースをキャッシュするように知らせるには、レスポンスの HTTP ヘッダを使用する。
例えば次のレスポンスヘッダはキャッシュの有効期間を1時間に設定しており、1時間はリクエストしてこなくていいことをクライアントに明示している。

Cache-Control: max-age=3600

Expires ヘッダをクライアントに返すとキャッシュの有効期限を日時で指定する事ができる。Cache-Control: max-age=xxx がある場合は Expires は無視される。

では次に Cache-Controle: max-age=xxx で指定した時間を過ぎたときのブラウザの動きを説明する。

レスポンスヘッダで指定されたキャッシュの有効期限が過ぎてもリソースが更新されていない場合もある。むしろ変更されていないほうが多いのではないだろうか。
更新されているかはサーバに問い合わせてみないとわからないのでクライアントはサーバにリクエストを送ることになるが、リソースが更新されていない場合、サーバはレスポンスボディを返さずにクライアントにキャッシュを使うように知らせることができる。このときのリクエストを条件付きリクエストと呼ぶ。

ブラウザに条件付きリクエストを行わせるには、レスポンスヘッダに Etag を含めて返す。

Etag: W/"5e88d7cf-1e1e"

Etag の値はリソースの状態を文字列で表したもので、ハッシュで実装したりする。リソースが変更されると Etag の値も変更される。
クライアントは受け取った Etag の値をリクエストの If-None-Match ヘッダの値として送信し、リソースに変更があった場合、サーバは新しいリソースをクライアントに返す。
リソースに変更がない場合、サーバはステータスコード 304 Not Modified を返し、レスポンスボディを空で返すので通信量を節約することができる。クライアントは Cache-Controle: max-age=xxx の有効期限内のときと同じようにクライアントキャッシュを表示に使用する。
Etag と If-None-Match のやり取りを条件付きリクエストと呼ぶ。

レスポンスヘッダの Last-Modified と リクエストヘッダの If-Modified-Since については省略。

紛らわしいのが次のキャッシュヘッダで、このレスポンスヘッダが返ったときブラウザはリソースをキャッシュする。

Cache-Control: no-cache

これはキャッシュしないというものではなく、キャッシュの利用に関して毎回サーバに問い合わせるというもの。Cache-Controle: max-age=0 とほぼ同じで問い合わせには Etag を用いる。

キャッシュさせない

クライアントにリソースをキャッシュしないように示す場合は次のヘッダを返す。

Cache-Control: no-store

ここまで出てきた no-cache や no-store はディレクティブと呼び、キャッシュ可能性を示すのに使用する。

他にも private や public など共有キャシュ・プライベートキャッシュを表すディレクティブがあるが、このあたりは REST の Layered System について勉強してからプロキシなども交えて言及しようと思っている。


  1. HTTP 条件付きリクエスト
  2. Expires
  3. 渋川よしき『Real World HTTP』O'REILLY 2017年6月