Ruby-on-rails 如何在 Rails 中防止浏览器页面缓存
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/711418/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How to prevent browser page caching in Rails
提问by Jason Butler
Ubuntu -> Apache -> Phusion Passenger -> Rails 2.3
Ubuntu -> Apache -> Phusion 乘客 -> Rails 2.3
The main part of my site reacts to your clicks. So, if you click on a link, it will send you on to the destination, and instantly regenerate your page.
我网站的主要部分会对您的点击做出反应。因此,如果您单击链接,它会将您发送到目的地,并立即重新生成您的页面。
But, if you hit the back button, you don't see the new page. Unfortunately, it's not showing up without a manual refresh; it appears the browser is caching it. I want to make sure the browser does not cache the page.
但是,如果您点击后退按钮,您将看不到新页面。不幸的是,它不会在没有手动刷新的情况下出现;看来浏览器正在缓存它。我想确保浏览器不会缓存页面。
Separately, I dowant to set far-future expiration dates for all my static assets.
另外,我确实想为我的所有静态资产设置远期到期日期。
What's the best way to solve this? Should I solve this in Rails? Apache? Javascript?
解决这个问题的最佳方法是什么?我应该在 Rails 中解决这个问题吗?阿帕奇?Javascript?
Thanks for all your help, Jason
谢谢你的帮助,杰森
Alas. Neither of these suggestions forced the behavior I'm looking for.
唉。这些建议都没有强迫我正在寻找的行为。
Maybe there's a javascript answer? I could have rails write out a timestamp in a comment, then have the javascript check to see if the times are within five seconds (or whatever works). If yes, then fine, but if no, then reload the page?
也许有一个javascript答案?我可以让 rails 在评论中写出一个时间戳,然后让 javascript 检查时间是否在五秒内(或任何有效的时间)。如果是,那很好,但如果不是,则重新加载页面?
Do you think this would work?
你认为这会奏效吗?
Thanks for all your help,
感谢你的帮助,
Jason
杰森
回答by Jason Butler
Finally figured this out - http://blog.serendeputy.com/posts/how-to-prevent-browsers-from-caching-a-page-in-rails/in application_controller.rb
终于想通了 - http://blog.serendeputy.com/posts/how-to-prevent-browsers-from-caching-a-page-in-rails/inapplication_controller.rb
After Rails 5:
在 Rails 5 之后:
class ApplicationController < ActionController::Base
before_action :set_cache_headers
private
def set_cache_headers
response.headers["Cache-Control"] = "no-cache, no-store"
response.headers["Pragma"] = "no-cache"
response.headers["Expires"] = "Mon, 01 Jan 1990 00:00:00 GMT"
end
end
Rails 4 and older versions:
Rails 4 及更早版本:
class ApplicationController < ActionController::Base
before_filter :set_cache_headers
private
def set_cache_headers
response.headers["Cache-Control"] = "no-cache, no-store"
response.headers["Pragma"] = "no-cache"
response.headers["Expires"] = "Mon, 01 Jan 1990 00:00:00 GMT"
end
end
回答by Sacre
回答by erik
I have used this line with some success in the controller. It works in Safari and Internet Explorer but I haven't seen it work with Firefox.
我在控制器中使用了这条线并取得了一些成功。它适用于 Safari 和 Internet Explorer,但我还没有看到它适用于 Firefox。
response.headers["Expires"] = "#{1.year.ago}"
For your second point, if you use the the rails helper methods like
对于你的第二点,如果你使用 rails helper 方法,比如
stylesheet_link_tag
and leave the default settings on your webserver, the assets are typically cached pretty well.
并在您的网络服务器上保留默认设置,资产通常会被很好地缓存。
回答by Roman
The cleaner way would be to write a Rack middleware, which changes the Cache-Control header based on some logic (for example, only for application/xml mime-type). Or, for an uglier, but still working approach, one could change the ActionDispatch::Response::DEFAULT_CACHE_CONTROL constant to 'no-cache'. Of course, if the controller and/or action granularity is required, then it's better to do this in the controller.
更简洁的方法是编写一个 Rack 中间件,它根据某些逻辑(例如,仅针对 application/xml mime-type)更改 Cache-Control 标头。或者,对于更丑陋但仍然有效的方法,可以将 ActionDispatch::Response::DEFAULT_CACHE_CONTROL 常量更改为“无缓存”。当然,如果需要控制器和/或动作粒度,那么最好在控制器中执行此操作。
回答by BalinKingOfMoria Reinstate CMs
Point of note: You can't conditionally clear the cache (like if a before_filteronly calls reset_cacheif the user's already been there). You need to unconditionallyclear the cache, because the browser won't make a new request just to see if this time, it needs to reload, even though it didn't need to last time.
注意点:您不能有条件地清除缓存(就像 abefore_filter仅reset_cache在用户已经在那里的情况下才调用)。您需要无条件地清除缓存,因为浏览器不会只是为了看看这次是否需要重新加载,即使它不需要上次也不会发出新请求。
Example:
例子:
before_filter :reset_cache, if: :user_completed_demographics?
won't work to prevent users from coming back after they've been there, since the browser uses the original cache headers on the Back button.
无法阻止用户在访问后返回,因为浏览器使用“后退”按钮上的原始缓存标头。
before_filter :reset_cache
will work, however (after refreshing the page and clearing the cache from before you added this, obviously), since, on the first request, the browser will get the no-cache, no-store, ...and apply it to future page loads.
但是,会起作用(显然,在添加此之前刷新页面并清除缓存之后),因为在第一次请求时,浏览器将获取no-cache, no-store, ...并将其应用于未来的页面加载。
回答by Joshua Pinter
no_cache_controlGem.
no_cache_control宝石。
If you need to do this for all responses, e.g. to pass a penetration test (BURP, Detectify, etc.), you can install this Gem on Rails 4+ in order to add the following headers to all responses:
如果您需要对所有响应执行此操作,例如通过渗透测试(BURP、Detectify 等),您可以在 Rails 4+ 上安装此 Gem,以便将以下标头添加到所有响应:
Cache-Control: no-cache, no-store, max-age=0, must-revalidate
Pragma: no-cache
Expires: -1
Works like a charm and is really the right way to go for secure, HTTPS web applications that require authentication to do anything.
像魅力一样工作,确实是安全的 HTTPS Web 应用程序的正确方式,这些应用程序需要身份验证才能执行任何操作。

