Rails 如何禁用 Rack Cache 呢?

jayliud · 2015年03月06日 · 最后由 jayliud 回复于 2015年03月08日 · 2107 次阅读

最近遇到个棘手的问题,google 后发现有人有一样的问题,但没答案。不知道论坛有人帮忙看看么?

I am attempting to stream a CSV file from a Rails 3.2 application. All works as expected IF I disable Rack-Cache... but I really want to keep the caching if possible. Setting 'Cache-Control: no-cache' for the response didn't help.

Here is my SO post on the topic: http://stackoverflow.com/questions/9930564/possible-to-disable-rack-cache-on-a-per-request-basis-in-rails-3-2

Is Rack-Cache incompatible with streaming responses??? Can anyone think of a way to disable Rack-Cache for this one request???

middleware delete 就好了

#1 楼 @huacnlee 但这样整个项目就完全没有用 rack::cache 呀,我现在只想一个 action 中禁用掉 rack::cache

#2 楼 @jayliud rails 接收到的已经是 rack 处理过的数据,所以你只能在 controller 里做处理了

#3 楼 @foxzool 关键是处理了,还是没有用

5 楼 已删除

#4 楼 @jayliud 前面想能否用 mount 另一个 rack application 来实现,但仔细看了一下,解决不了问题。

#5 楼 @Rei 我是真心在求助,不回答请忽略

有人预到类似的问题吗?

想到一个 hacking 的做法,没有经过验证,只是一个思路。

在 initializers 里面创建一个 Rack-Cache class,然后 override 里面的 call 方法,针对你需要的 url 去 bypass 这个 middleware,类似下面这样:

class Rack::Cache

  def call(env)
    if url_matching?
      super(env)
    else
      @app.call(env)
    end
  end

end

@jayliud 如果你对 Rails 源码比较熟悉,就会发现无法做到在控制器中删除指定的中间件。所以 @rei 才会说这是 x-y 问题。Rails controller 是注册在 Rack 众多中间件的最上一层,它无力控制其他中间的处理。充其量它可以添加新的中间件,于是 Rails4 中增加了 Controller.use 能力。

这个问题不知道你使用的 Rails 版本,如果是 4.1 以上 ( 也许 3.x 的某个版本就已经 Ok 了 ), stream & live 两种处理方式已经自动设置了 no-cache.

如果不能升级 Rails 版本,也许手动设定 headers['Cache-Control'] = 'no-cache' 就会 OK, 也许你特定的版本 Rack::Cache 中间件不会检查这个头部会覆盖它,这样你就只能去研究下它的源码,看看有无可以 Hack 的手段:actionpack 里面的 lib/action_dispatch/http/cache.rb.

其他的办法,mount 自己的中间件,大家已经热情给你说了,但据我所知,也基本不可行。不如试试我给的建议。

一个想法,可以考虑写一个中间件 站在 Rack::Cache 前面 或者就放在 config.ru 里面。如果 match URL 就删掉 HTTP 上面相关的 headers - 清空或者是设置成让 cache 失效

如果前面有 Nginx 也可以考虑放到那里面

#10 楼 @lyfi2003 非常感谢你的回答,惭愧没有像大家那么深入研究源代码。。。升级成本较大看看能否 hack 了

#9 楼 @lgn21st 好像你的方案最简单可行,我尝试一下看看,能否实现在控制器中删除指定的中间件

#13 楼 @jayliud 我觉得 @lyfi2003#10 楼 提到的方案你可以试试看,在指定的 action 里面,添加下面一行:

response.headers["Cache-Control"] = "no-cache"

#14 楼 @lgn21st 试过了没有用,可能和版本有关系

需要 登录 后方可回复, 如果你还没有账号请 注册新账号