我在我的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上开了一张票。
答案 0 :(得分: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。'我将root设置为'public'目录。
请求此路径:
<强> /assets/jquery-e8da439bbc8fd345e34ac57c6a216318.min.js 强>
应该在这个文件中找到它:
公开/资产/ jquery的-e8da439bbc8fd345e34ac57c6a216318.min.js 强>
这应该直接从public / assets目录中提供任何资产,而不是完全按Rails :: Cache,这将阻止它将资产存储在Rails cache_store中。这只有在生产中运行'rake assets:precompile'时才有效,否则'public / assets'中不会有预编译资产。
答案 1 :(得分:7)
原始海报希望防止静态资产进入常规Rails缓存,这导致他们想要禁用Rack :: Cache。而不是这样做,更好的解决方案是配置Rack :: Cache使用单独的缓存而不是一般的Rails缓存。
Rack :: Cache应针对实体存储与元存储进行不同的配置。 Rack :: Cache有两个不同的存储区域:元存储和实体存储。 Metastore保存有关每个缓存条目的高级信息,包括HTTP请求和响应头。该区域存储以高频率访问的小块数据。实体存储缓存响应主体内容,虽然访问频率低于元数据库,但它可以是相对大量的数据。
以下配置将memcached中的Metastore信息缓存,但将资产的实际主体缓存到文件系统。
使用memcached gem:
config.action_dispatch.rack_cache = {
:metastore => 'memcached://localhost:11211/meta',
:entitystore => 'file:tmp/cache/rack/body',
:allow_reload => false
}
使用dalli gem
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
答案 2 :(得分:3)
您可以关闭资产管道文件的缓存,同时保留其他缓存:
config.assets.cache_store = :null_store
这应该阻止Sprockets缓存任何东西。
答案 3 :(得分:1)
另一种解决同一问题的方法就是使用ActionDispatch :: Static中间件代替Rack :: 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请求中“public”中是否存在文件,无论路径如何。
Rack :: Static首先不检查文件,它在文件上调用Rack :: File.new,所以如果它不存在则会返回404,它不会传递请求中间件链。
如果ActionDispatch :: Static在其路径中找不到该文件,它将继续沿着机架中间件链(Rails堆栈的其余部分)继续运行。
最后,无论ActionDispatch :: Static在'public'中找不到它,它都只会传递给Rails堆栈。所以Rails最终将提供ActionDispatch :: Static无法找到的资产。这解决了Rack :: Cache无法找到的资产问题,但由于每个请求都会触发文件检查,因此资源也更加密集。