静的ファイル
Cache-controlヘッダを指定する
Expiresと同じく、キャッシュの有効期限を指定できるレスポンスヘッダ。HTTP1.1で定義されたもので、有効期限だけでなくキャッシュに関する詳細な設定を行える。大多数のブラウザが HTTP1.1に対応しているので、Expiresではなく、Cache-Controlヘッダを利用するのがよい。
説明
-
max-age : キャッシュの有効期限を設定する。(相対時間で指定し、単位は秒。)
例えばブラウザのキャッシュを1年間有効にしたい場合は、次のように指定する。
有効期限の間はキャッシュが利用され、サーバに問い合わせが発生しないようにできる。
Cache-Control: max-age=31557600
-
private : そのコンテンツがそのユーザのみに対して提供されたものであり、キャッシュを他のユーザと共有しない。
-
must-revalidate : キャッシュに記録されているコンテンツが現在も有効かどうかを、必ずサーバに問い合わせる設定。
Rails では
以下がデフォルトでレスポンスに付与している。
Cache-Control: max-age=0, private, must-revalidate
Cache-Control ヘッダを Rails から指定したい場合は、コントローラで次のように記述する。
def index
expires_in 1.hour
# => Cache-Control: max-age=3600, private
end
expires_in はオプションとして、public と must_revalidate を T/F で指定する。
ブラウザにキャッシュさせたくない場合
def index
expires_now
end
# => Cache-Control: no-cache
Nginx で同様の設定をするには
location ~ ^/assets/ {
add_header Cache-Control "max-age=31557600, public";
}
これで、有効期限の間はキャッシュが利用され、サーバに問い合わせが発生しないが、活用できるのは静的ファイルに限られる。
動的ファイル
ETag、Last-Modified ヘッダを指定する
説明
-
ETag(If-None-Match)
そのコンテンツを示すユニークな値を返すレスポンスヘッダで、コンテンツの更新の有無を確認するために用いられる。同じURLへリクエストを行った場合、コンテンツが更新されていなければ ETag ヘッダの値は毎回同じ、コンテンツが更新されていれば ETag ヘッダを変化させるという決まり。Etag ヘッダを設定すると次回のリクエストのヘッダに、If-None-Match というリクエストヘッダを付し、この値を比較し、ページが更新されていなければ 304 - Not Modified のステータスコードのみを返す。 -
Last-Modified(If-Modified-Since)
Etag と同様に、条件付き GET リクエストのためのレスポンスヘッダ。名前の通りそのURLが最後に更新された時刻を出力する。Last-Modified ヘッダを設定すると If-Modified-Since というリクエストヘッダを用いる。
Rails では
def index
@article = Article.last
end
# => 200 OK
def index
@article = Article.last
fresh_when @article
end
# => 304 Not Modified
# => Etag : "<MD5>"
# => Last-Modified: <日付>
fresh_when
Etag と Last-Modified をレスポンスヘッダに付与する。
fresh_when は Rails4.2 から template の更新が考慮されるように修正されたみたいです。
rails commit log流し読み(2014/08/17) - なるようになるブログ : http://y-yagi.hatenablog.com/entry/2014/08/18/063227
コントローラレベルでの ETag
class ArticleController < ApplicationController
etag { current_user.try(:id) }
def index
@article = Article.find(params[:id])
fresh_when(@article)
end
end
etag はブロックの評価結果を ETag の値を算出する元データに追加します。ログインユーザごとに ETag の値を変更したい場合に有効。
コード
今回使ったメソッドは、
ActionController::ConditionalGet
にある。
https://github.com/rails/rails/blob/b40bd16b7b0810b9d5621339f243c4a9569ceb96/actionpack/lib/action_controller/metal/conditional_get.rb
- expires_in, expires_now
- fresh_when
- stale? (上で紹介していない)
適切なEtagとLast-Modified-Sinceヘッダを設定し、現在のリクエストがstale (腐りかけた; 完全な処理をする必要がある) か、それともfresh (新鮮な; ウェブクライアントがキャッシュされたコンテンツをつかえる) かを真偽値で返す。
参考・引用
以下の書籍、記事から多く引用・参考にさせていただきました。
スライドや図、サンプルコードなどもあってとてもわかりやすいです。
- WEB+DB PRESS Vol.70|技術評論社 : http://gihyo.jp/magazine/wdpress/archive/2012/vol70
- High Performance Rails (long edition) // Speaker Deck : https://speakerdeck.com/mirakui/high-performance-rails-long-edition
- Ruby on Rails のConditionalGet について - Qiita : http://qiita.com/cuzic/items/326e8600dc596de6636a
- Controller に関する変更点 | TECHSCORE(テックスコア) : http://www.techscore.com/tech/Ruby/rails-4.0/controller/
- Http caching ruby rails · herokaijp/devcenter Wiki : https://github.com/herokaijp/devcenter/wiki/Http-caching-ruby-rails
- ActionController::ConditionalGet : http://api.rubyonrails.org/classes/ActionController/ConditionalGet.html#method-i-stale-3F