19

Rails 3.1 アプリケーションで CloudFlare CDN を使用しています。Cloudflare は、DNS レベルで機能する CDN です。静的アセットへの最初のヒットで、CloudFlare はそれをアプリからロードし、CDN にキャッシュします。そのアセットに対する今後のリクエストは、アプリではなく CDN から読み込まれます。

私が抱えている問題は、コントローラーのキャッシュをtrueに設定した場合です:

config.action_controller.perform_caching = true

Rack::Cache ミドルウェアを有効にします。Rails は静的アセットのデフォルトのキャッシュ制御設定を設定するため、それらのアセットは Rails.cache ストアに書き込まれます。その結果、私のキャッシュ ストア (私の場合は redis) は、ハッシュ キーとしての URL を持つ静的アセットでいっぱいになります。

残念ながら、Cloudflare とユーザーのブラウザーがアセットをキャッシュする方法に影響を与えずに、静的アセット キャッシュ コントロール ヘッダーをオフにすることはできません。コントローラーのキャッシュをオフにできません。または、ページ/アクション/フラグメントのキャッシュが失われます。Rack::Cache ミドルウェアを削除しても同じ結果になります。

他のアイデアはありますか?

更新: GitHub here でチケットをオープンしました。

4

4 に答える 4

8

多くの実験の後、config/application.rb でこれを行うことになりました。

if !Rails.env.development? && !Rails.env.test?
  config.middleware.insert_before Rack::Cache, Rack::Static, urls: [config.assets.prefix], root: 'public'
end

これにより、Rack::Cache へのリクエストの前に Rack::Static ラック ミドルウェアが追加されます。Rack::Static ミドルウェアは、一致するプレフィックスを持つ URL をルート ディレクトリに提供します。ここでは、config.assets.prefix を URL プレフィックスとして指定しています。デフォルトは「/assets」です。ルートを「パブリック」ディレクトリに設定しています。

このパスのリクエスト:

/assets/jquery-e8da439bbc8fd345e34ac57c6a216318.min.js

このファイルでそれを見つける必要があります:

パブリック/アセット/jquery-e8da439bbc8fd345e34ac57c6a216318.min.js

これにより、Rails::Cache にヒットするのではなく、 public/assets ディレクトリから直接アセットを提供する必要があります。これにより、Rails cache_store にアセットが保存されなくなります。これは、本番環境で「rake assets:precompile」を実行した場合にのみ機能します。それ以外の場合、「public/assets」にプリコンパイルされたアセットはありません。

于 2011-08-09T23:06:15.953 に答える
7

元の投稿者は、静的アセットが一般的な Rails キャッシュに入るのを防ぎたいと考えていたため、Rack::Cache を無効にする必要がありました。これを行うよりも、一般的な Rails キャッシュとは別のキャッシュを使用するように Rack::Cache を構成することをお勧めします。

Rack::Cache は、エンティティ ストレージとメタ ストレージでは異なる構成にする必要があります。Rack::Cache には、メタ ストアとエンティティ ストアの 2 つの異なるストレージ領域があります。メタストアは、HTTP 要求および応答ヘッダーを含む各キャッシュ エントリに関する高レベルの情報を保持します。この領域には、頻繁にアクセスされるデータの小さなチャンクが格納されます。entitystore は、metastore ほど頻繁にアクセスされませんが、比較的大量のデータになる可能性のある応答本文のコンテンツをキャッシュします。

以下の構成では、メタストア情報は memcached にキャッシュされますが、アセットの実際の本体はファイル システムにキャッシュされます。

memcached gem の使用:

config.action_dispatch.rack_cache = {
  :metastore    => 'memcached://localhost:11211/meta',
  :entitystore  => 'file:tmp/cache/rack/body',
  :allow_reload => false
}

ダリ宝石の使用

config.action_dispatch.rack_cache = {
  :metastore    => Dalli::Client.new,
  :entitystore  => 'file:tmp/cache/rack/body',
  :allow_reload => false
}

ちなみに、この構成は Heroku の推奨事項です: https://devcenter.heroku.com/articles/rack-cache-memcached-static-assets-rails31

于 2012-05-29T14:56:20.070 に答える
3

次の方法で、アセット パイプライン ファイルのキャッシュをオフにし、他のキャッシュをそのままにしておくことができます。

config.assets.cache_store = :null_store

これにより、Sprockets が何もキャッシュしないようにする必要があります。

于 2013-06-21T23:44:36.433 に答える
1

同じ問題とこの問題を解決する別の方法は、次のように Rack::Static の代わりに ActionDispatch::Static ミドルウェアを使用することです。

if !Rails.env.development? && !Rails.env.test?
  config.middleware.insert_before Rack::Cache, ::ActionDispatch::Static, 'public', config.static_cache_control
end

Rack::Static と ActionDispatch::Static の違いは何ですか?

  • Rack::Static は、リクエスト URL と照合するために URL プレフィックスの配列を受け取ります。この場合、リクエスト パスが「/assets」で始まる場合にのみファイルをチェックします。

  • ActionDispatch::Static は、パスに関係なく、すべての GET/HEAD リクエストで「パブリック」にファイルが存在するかどうかをチェックします。

  • Rack::Static は最初にファイルをチェックせず、ファイルに対して Rack::File.new を呼び出します。そのため、ファイルが存在しない場合は 404 を返し、リクエストをミドルウェア チェーンに渡しません。

  • ActionDispatch::Static がそのパスでファイルを見つけられない場合、ラック ミドルウェア チェーン (Rails スタックの残り) を下に進みます。

最終的に、ActionDispatch::Static が 'public' で見つけられないものは何であれ、Rails スタックに渡されます。したがって、Rails は ActionDispatch::Static が見つけられないアセットを提供することになります。これにより、Rack::Cache によってアセットが見つからないという私の問題は解決されますが、すべてのリクエストがファイル チェックをトリガーするため、リソースをより集中的に使用します。

于 2012-02-17T19:53:45.193 に答える