Ruby on rails 如何防止Rails 3.1将静态资产缓存到Rails.cache?

Ruby on rails 如何防止Rails 3.1将静态资产缓存到Rails.cache?,ruby-on-rails,caching,ruby-on-rails-3.1,asset-pipeline,cloudflare,Ruby On Rails,Caching,Ruby On Rails 3.1,Asset Pipeline,Cloudflare,我正在Rails 3.1应用程序上使用CloudFlare CDN。Cloudflare是在DNS级别工作的CDN。在第一次命中静态资产时,CloudFlare会从您的应用程序加载该资产,然后将其缓存到CDN中。将来从CDN而不是应用程序加载该资产的请求 我遇到的问题是,如果将控制器缓存设置为true: config.action_controller.perform_caching = true 它启用Rack::Cache中间件。因为Rails为静态资产设置了默认的缓存控制设置,所以这些资

我正在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上打开了一张罚单。

经过大量实验,我最终在我的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中间件。静态中间件提供带有根目录匹配前缀的URL。这里我将config.assets.prefix作为我的url前缀,默认为“/assets”。我将根目录设置为“public”目录

对此路径的请求:

/assets/jquery-e8da439bbc8fd345e34ac57c6a216318.min.js

应在此文件中找到它:

public/assets/jquery-e8da439bbc8fd345e34ac57c6a216318.min.js


这应该直接服务于public/assets目录之外的任何资产,而不是访问Rails::Cache,这将阻止它将资产存储在Rails缓存存储中。只有在生产环境中运行“rake assets:precompile”时,这才有效,否则“public/assets”中不会有预编译的资产。

解决相同问题的另一种方法是使用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找不到资产的问题,但由于每个请求都会触发文件检查,因此资源更加密集。

原始海报希望防止静态资产进入通用Rails缓存,这导致他们想要禁用Rack::Cache。与此相反,更好的解决方案是将Rack::Cache配置为使用单独的缓存,而不是普通的Rails缓存

对于实体存储和元存储,Rack::Cache的配置应该有所不同。Rack::Cache有两个不同的存储区域:元存储和实体存储。metastore保存有关每个缓存项的高级信息,包括HTTP请求和响应头。该区域存储以高频率访问的小块数据。entitystore缓存响应正文内容,虽然其访问频率低于metastore,但响应正文内容可能是相对大量的数据

下面的配置将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的推荐配置:

您可以关闭资产管道文件的缓存,同时保留其他缓存:

config.assets.cache_store = :null_store

这应该可以防止链轮缓存任何东西。

当你说静态资产时,你是指链轮生成的文件吗?是的,我是。将散列附加到文件名后。一个随机的旁白-如何让您的资产ID显示在文件名中?您是否已将
config.assets.precompile
设置为包含所有要预编译的文件?@Kevin您可以在production.rb中设置
config.action\u controller.perform\u caching=true
“每个请求都将触发文件检查”--你是指对应用程序的每个请求,还是仅对公共应用程序的请求?另外,在第一个要点中,你的意思是说ActionDispatch::Static?不对。Rack::Static采用一组url前缀。它们甚至被称为“url”“。如果您直接比较每个要点中每个解决方案的行为,会非常有帮助--现在这有点含糊不清。我希望这会在Rails中得到修复,这只是一个临时修复。当我有机会的时候,我会考虑重新格式化它。这在Rails3.2上对我有效,因为上面所有的答案只让我达到了一半。谢谢