HTTPキャッシュ
RFC2616 Hypertext Transfer Protocol (HTTP/1.1): CachingではHTTPキャッシュの目的を以下のように定めています。
HTTP/1.1 のキャッシングの目的はリクエストを送る必要を無くしたり、全レスポンスを送る必要を無くす事です。
BEAR.Sundayでは@Cacheableアノテーションによるサーバーサイドでのキャッシュが仕組みがありますが、これをRFC7234 HTTPキャッシュにも適用してネットワークキャッシュ(クライアントサイドキャッシュ)をサポートします。
REST標準のキャッシュ制約に従う事でRFC7234をサポートしたHTTPクライアントでは、クラアイントでのコーディングなしにクライアントサイドキャッシュやキャッシュサーバーの使用が可能になります。
Cache-Controlヘッダー
ディレクティブ
| ディレクティブ | 説明 |
|---|---|
| public | クライアント間の共有キャッシュの利用 |
| private | クライアントでキャッシュを共有しない |
| no-store | キャッシュしません |
| no-cache | キャッシュの利用にオリジンサーバーへの検証が必要。1 |
| must-revalidate | 期限の切れたキャッシュの利用に必ず検証が必要。 |
| max-age | キャッシュの有効期限 |
| s-maxage | 共有キャッシュの有効期限 |
publicとprivate
publicの場合、レスポンスにHTTP認証が関連付けられているとしても、レスポンスのステータスコードが通常キャッシュ可能になっていない場合でもキャッシュできます。通常はmax-ageなど明示的なキャッシュ情報によってレスポンスがキャッシュ可能であることが指定されているためpublicは必要ありません。
一方、privateレスポンスは、ブラウザのキャッシュには格納できますが、通常、対象ユーザーは1人のため、中間キャッシュに格納することは認められません。たとえば個人的なユーザー情報はそのユーザーのクライアントでのみキャッシュされCDNではキャッシュされません。
no-cacheとno-store
no-cacheはキャッシュ可能かどうか、つまりレスポンスに変更があったかどうかを確認する必要があることを示します。リクエストヘッダーの検証トークン(ETag)を検査し、リソースに変更がなければHTTPコード304を返答し、レスポンスボディを省略する事ができます。
no-storeは単純にレスポンスのすべてのキャッシュを禁止します。
###
最適なCache-Control ポリシーの定義2

@Cacheable
例)サーバーサイドで30秒キャシュ、クライアントでも30秒キャシュ。
サーバーサイドで指定してるのでクライアントサイドでも同じ秒数でキャッシュされます。この時に@HttpCacheアノテーションは必要ありません。
use BEAR\RepositoryModule\Annotation\Cacheable;
/**
* @Cacheable(expirySecond=30)
*/
class CachedResource extends ResourceObject
{
例)指定した有効期限($body['expiry_at']の日付)までサーバー、クライアント供にキャッシュ
use BEAR\RepositoryModule\Annotation\Cacheable;
/**
* @Cacheable(expiryAt="expiry_at")
*/
class CachedResource extends ResourceObject
{
@HttpCache
例)プライベートで30秒キャシュ
認証情報などクライアントで共用できないプラベート情報はisPrivateを指定します。
use BEAR\RepositoryModule\Annotation\HttpCache;
/**
* @HttpCache(isPrivate=true, max-age=60)
*/
class CachedResource extends ResourceObject
{
例)更新されていないか都度確認します3。
use BEAR\RepositoryModule\Annotation\NoHttpCache;
/**
* @HttpCache(noCache=true)
*/
class CachedResource extends ResourceObject
{
例)上記と同じですが、更新されていないならプライベートキャッシュのみを利用します。
use BEAR\RepositoryModule\Annotation\NoHttpCache;
/**
* @HttpCache(is_private=true, noCache=true)
*/
class CachedResource extends ResourceObject
{
@NoHttpCache
クライアントキャッシュしない時は@NoHttpCacheで指定します。
use BEAR\RepositoryModule\Annotation\NoHttpCache;
/**
* @NoHttpCache
*/
class UncacheableResource extends ResourceObject
{
この時に@Cacheableでサーバーサイドでキャッシュすることは可能です。
レスポンスヘッダ
キャッシュされたレスポンスにはLast-Modified、Etag、Ageヘッダーが付加されます。
Last-Modifiedヘッダーはキャッシュが保存された時間、Ageヘッダーは保存されてからの経過時間が表示されます。
キャッシュがヒットしたかどうかはAgeヘッダー(キャッシュ生成後経過秒数)の存在で分かります。4
リクエストヘッダ
Varyヘッダーで指定したリクエストヘッダでレスポンスが変わることを指定できます。言語や、ユーザーエージェント等、認証ID別にキャッシュを持つことができます。
RFC7234対応クライアント
- iOS NSURLCache
- Android HttpResponseCache
- PHP guzzle-cache-middleware
- JavaScript(Node) cacheable-request
- Go lox/httpcache
- Ruby faraday-http-cache
- Python requests-cache
有効なキャッシュのために
- 一貫したURIを使用する。5
- クラアイントサイドでのキャッシュを優先して検討する
- 適切な有効期限(
max-age)を設定する。 - ユーザー単位で格納されるリソースも
privateでキャッシュする。 - 本当にキャッシュできないコンテンツのみ
no-storeを使用する。 - HTTP APIクライアントにRFC7234対応クライアントを使用する。
Link
- HTTP Caching - Client and Network Caching with RFC 7234
- Speeding Up APIs/Apps/Smart Toasters with HTTP Response Caching