1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

Railsのpublic_file_serverとキャッシュ制御

1
Posted at

背景

  • Railsの config/environments/production.rb を見ていたconfig.public_file_server.headers という設定があった
  • キャッシュ制御の設定っぽいけど、なぜこの値なのか、どういう仕組みで安全なのかがわからなかったので調べた

public_file_serverとは

Railsが public/ ディレクトリにある静的ファイル(CSS, JS, 画像など)を配信するための仕組み

関連する設定は2つある

# config/environments/production.rb

config.public_file_server.enabled = ENV["RAILS_SERVE_STATIC_FILES"].present?
config.public_file_server.headers = { "cache-control" => "public, max-age=#{1.year.to_i}" }

enabled — 静的ファイル配信の有効/無効

本番環境では通常、NginxやCDNが静的ファイルの配信を担当する。そのためRails自身が配信する必要はなく、デフォルトでは無効になっている

ただしHerokuのようなPaaS環境ではNginxを挟まずPumaが直接リクエストを受けるため、Rails自身が静的ファイルを配信する必要がある。環境変数 RAILS_SERVE_STATIC_FILES で切り替えられるようになっているのはそのため

headers — 配信時のHTTPレスポンスヘッダー

静的ファイルを配信するときに付与するHTTPレスポンスヘッダーを設定できる

Cache-Controlヘッダーの中身

cache-control: public, max-age=31536000

この設定には2つの指示が含まれている

public

「ブラウザだけでなく、CDNやプロキシサーバーもキャッシュしてOK」という意味

対義語は private で、これはブラウザだけがキャッシュできる(CDNやプロキシは不可)。ユーザー固有のデータ(マイページのHTMLなど)には private を使う。CSSやJSのような全ユーザー共通のファイルは public で問題ない

max-age=31536000

「31536000秒(= 1年間)はサーバーに再リクエストせず、キャッシュを使ってOK」という意味

つまりブラウザは一度ダウンロードしたファイルを1年間はローカルキャッシュから返す。サーバーへのリクエスト自体が発生しないので、表示速度の向上とサーバー負荷の軽減の両方が得られる

なぜ1年もキャッシュして大丈夫なのか

「ファイルを更新したのに古いキャッシュが使われ続けるのでは?」と思うかもしれないが、Railsのアセットパイプラインがこの問題を解決している

ダイジェスト付きファイル名

Railsはアセットをコンパイルするとき、ファイルの中身からハッシュ値(ダイジェスト)を計算し、ファイル名に付与する

application-a1b2c3d4e5f6.css
application-a1b2c3d4e5f6.js

CSSやJSの中身を1文字でも変更すると、ダイジェストが変わり、ファイル名も変わる

# 修正前
application-a1b2c3d4e5f6.css

# 修正後(中身が変わったのでダイジェストも変わる)
application-f7g8h9i0j1k2.css

HTMLから参照されるファイル名も新しいものに切り替わるので、ブラウザは「見たことのない新しいファイル」として取得しにいく。古いファイルのキャッシュは参照されなくなるだけなので、キャッシュが1年残っていても問題にならない

この仕組みがあるから長期キャッシュが安全

まとめると、こういう流れになる

1. ブラウザが application-a1b2c3d4e5f6.css をリクエスト
2. サーバーが「1年間キャッシュしてOK」と返す
3. ブラウザが1年間キャッシュする
4. 開発者がCSSを修正してデプロイ
5. HTMLが参照するファイル名が application-f7g8h9i0j1k2.css に変わる
6. ブラウザは新しいファイル名でリクエスト → 新しいファイルを取得
7. 古い application-a1b2c3d4e5f6.css のキャッシュは使われなくなる

ファイル名が変わるから、キャッシュの無効化を気にする必要がない。これがRailsのアセットパイプラインとCache-Controlヘッダーの組み合わせが上手くいく理由

まとめ

  • config.public_file_server はRailsが public/ の静的ファイルを配信する仕組み
  • enabled は本番ではNginx/CDNが担当するので通常は無効、Herokuなどでは有効にする
  • headerscache-control: public, max-age=1年 を設定し、ブラウザキャッシュを活用する
  • 1年という長期キャッシュが安全なのは、アセットパイプラインのダイジェスト付きファイル名のおかげ
  • ファイル内容が変わればファイル名も変わるので、古いキャッシュが使われるリスクはない

参考

1
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?