java 如何正确防止缓存 302 重定向位置?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/36722857/
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 correctly prevent caching of 302 redirect location?
提问by user2418306
I've encountered next problem with Post/Redirect/Getpattern.
When performing GET
after redirect Chrome takes the page from cache.
So user sees stale data.
我遇到了Post/Redirect/Get模式的下一个问题。GET
在重定向后执行时,Chrome 从缓存中获取页面。所以用户会看到陈旧的数据。
I've tried following to force/support revalidation
我试过以下来强制/支持重新验证
if (request.checkNotModified(sinceLastTweet)) return null;
response.setHeader("Cache-Control", "no-cache");
response.setHeader("Last-Modified", String.valueOf(sinceLastTweet));
But only no-store
causes a server request.
但只会no-store
引起服务器请求。
Why Chrome takes the page from cache when performing redirect?
为什么 Chrome 在执行重定向时从缓存中获取页面?
@RequestMapping(method = GET)
public String home(ModelMap model, @PathVariable String username, HttpServletResponse response, WebRequest request) {
// response.setHeader("Cache-Control", "no-store");
List<Tweet> tweets = tweetRepository.findAll();
// long sinceLastTweet = tweets.get(0).getTimestamp().toEpochMilli();
// if (request.checkNotModified(sinceLastTweet)) return null;
// response.setHeader("Cache-Control", "no-cache");
// response.setHeader("Last-Modified", String.valueOf(sinceLastTweet));
model.addAttribute("tweets", tweets);
model.addAttribute("tweet", new Tweet());
model.addAttribute("username", username);
return "home";
}
采纳答案by Testo Testini
If one Chrome instance has cached page /username
the page is not hit by that Chrome as effect of the redirect because Chrome reads the Location
header and serves the cached page.
如果一个 Chrome 实例已缓存页面,则/username
该页面不会因为重定向而被该 Chrome 访问,因为 Chrome 会读取Location
标题并提供缓存页面。
Maybe one time you visited the page while trying cache headers and now your Chrome thinks it must cache it, maybe even forever.
也许有一次您在尝试缓存标题时访问了该页面,而现在您的 Chrome 认为它必须缓存它,甚至可能永远缓存它。
You need to invalidate the cache (with that Chrome) for the /username
page:
您需要使页面的缓存(使用该 Chrome)无效/username
:
- setup the
/username
page to be alwaysserved with headers that disable caching, like those suggested by rev_dihazum or how is done in Spring WebContentGenerator. - Clear the cache manually or visit
/username
and hit CTRL+R while being in the page: page will be actually requested, cache disabling headers will be read and from that moment the page will be again requested each time to the server, including when is requested as effect of a redirect.
- 将
/username
页面设置为始终使用禁用缓存的标头提供服务,例如 rev_dihazum 建议的标头或Spring WebContentGenerator 中的做法。 - 手动清除缓存或
/username
在页面中访问并点击 CTRL+R:将实际请求页面,将读取缓存禁用标头,从那时起,该页面将每次再次请求到服务器,包括何时请求为重定向的效果。
If the page is public and users, whose browsers you cannot control, have already cached it, then problem is worse and you may choose one of the following:
如果该页面是公开的,并且您无法控制其浏览器的用户已经对其进行了缓存,则问题会更严重,您可以选择以下一种方式:
- wait for cache to expire
- change name to the page
- add some random number, more or less as suggested by prad121, to the
Location
URL to make it unique, a variation of 2)
- 等待缓存过期
- 更改页面名称
- 添加一些随机数,或多或少如 prad121 所建议的,到
Location
URL 以使其唯一,变体 2)
Note that Last-Modified
time format is Tue, 15 Nov 1994 08:12:31 GMT
, you may use the setDateHeader
method to set it as a long
注意Last-Modified
时间格式是Tue, 15 Nov 1994 08:12:31 GMT
,您可以使用setDateHeader
方法将其设置为long
You may look into WebContentGeneratorto see other caching code in Spring.
您可以查看WebContentGenerator以查看 Spring 中的其他缓存代码。
回答by Troncador
1) You have to try to force Chrome to not use the cache,
1) 您必须尝试强制 Chrome 不使用缓存,
How to control web page caching, across all browsers?
Like the answer of that question suggest you have to put this header in the http response:
就像那个问题的答案一样,建议您必须将此标头放在 http 响应中:
response.header("Cache-Control: no-cache, no-store, must-revalidate"); // HTTP 1.1.
response.header("Pragma: no-cache"); // HTTP 1.0.
response.header("Expires: 0"); // Proxies.
2) You can make a little trick
2)你可以做一个小把戏
You can program to respond any request with the follow format with the same controller:
您可以编程以使用相同的控制器以以下格式响应任何请求:
http://localhost:8080/spitter/username-{timestamp}
Then you change your links in your page to have the last timestamp before send the request.
然后,您将页面中的链接更改为在发送请求之前具有最后一个时间戳。
In this case, event if chrome caches the page it doesn't matter.
在这种情况下,如果 chrome 缓存页面,则事件无关紧要。
Instead of timestamp you can use any other methodology, like "autoincrement" or "uuid".
您可以使用任何其他方法来代替时间戳,例如“自动增量”或“uuid”。
回答by dr. rAI
Maybe you can try using an ETag for your page.
也许您可以尝试为您的页面使用 ETag。
I am not exactly sure if I correctly understand your redirect scenario though.
不过,我不确定我是否正确理解了您的重定向场景。
Let's say you have some display page that contains a username
and you have some second page that provides Editingfor your data and you want to be able to change the username
there and press a button to save it an get back to the display page thereafter.
假设您有一些包含 a 的显示页面,username
并且您有一些第二页为您的数据提供编辑,并且您希望能够更改username
那里的内容,然后按一个按钮将其保存,然后返回显示页面。
One option would be to include the username
in the URL (like ...&username=Hyman
). Since the username has changed, the URL would change as well (i.e. ...&username=Jim
). In this case, Chrome would not have a cached version of the display page for Hyman and would get a fresh version of it from the server. (If you have any field that you don't want to mention explicitly in the URL you could calculate a checksum over all fields and add this as a parameter like ...&check=12345678
).
一种选择是将 包含username
在 URL 中(如...&username=Hyman
)。由于用户名已更改,因此 URL 也会更改(即...&username=Jim
)。在这种情况下,Chrome 不会有 Hyman 的显示页面的缓存版本,而是会从服务器获取它的新版本。(如果您有任何不想在 URL 中明确提及的字段,您可以计算所有字段的校验和并将其添加为参数,如...&check=12345678
)。
Another option would be to have the server generate an ETag - so let's look into this in detail. What we want is that the server app is in charge to tell the browser if the data needs a refresh or can be taken from the Cache, right?
另一种选择是让服务器生成一个 ETag - 所以让我们详细研究一下。我们想要的是服务器应用程序负责告诉浏览器数据是否需要刷新或可以从缓存中获取,对吗?
{ Please forgive me that I am not using your very example here since I am currently developing on a different Stack - however, I think your problem can be solved with your Java/Spring Stack the same way }
{ 请原谅我在这里没有使用您的示例,因为我目前正在不同的堆栈上进行开发 - 但是,我认为您的问题可以通过 Java/Spring Stack 以同样的方式解决 }
Have a look at the screenshot in the section Response Headersand about in the middle you see ETag. This id is generated by the server - so the server app is in control here. (Maybe this articlehelps you if you haven't implemented an ETag yet.)
查看Response Headers部分中的屏幕截图,大约在中间您会看到ETag。这个 id 是由服务器生成的 - 所以服务器应用程序在这里控制。(如果您还没有实现 ETag,这篇文章也许对您有所帮助。)
So what happens?As soon as the content changes on the server, the ETag changes as well - the Browsersees the ETag in the response, respects that the server is in charge and asks the server if the content has changed and if so kicks out the cached page with the expired content and requests a new one from the server.
那么会发生什么?一旦服务器上的内容发生变化,ETag 也会发生变化 -浏览器会在响应中看到 ETag,尊重服务器负责并询问服务器内容是否发生变化,如果发生变化,则将缓存页面踢出过期的内容并从服务器请求新的内容。
You have to make sure, of course, that as soon as the server learns that the user has changed from Hymanto Jim(or any other field accordingly) the server app generates the new ETag for this user's display page.
当然,您必须确保一旦服务器得知用户已从Hyman更改为Jim(或相应的任何其他字段),服务器应用程序就会为该用户的显示页面生成新的 ETag。
Hope it helps!
希望能帮助到你!
回答by prad121
Add some random numbers(current time in milisecs) at the end of the URL. like service URL is
在 URL 末尾添加一些随机数(以毫秒为单位的当前时间)。像服务 URL 是
http://localhost:7001/rest/getBook/5
So instead of making call to above URL, u append some random numbers at end while making the above service call
因此,不是调用上述 URL,而是在调用上述服务时在末尾附加一些随机数
/rest/getBook/5?_time-in-milisec
It requires little be tweaking of service call in javascript.
它几乎不需要在 javascript 中调整服务调用。
URL = http://localhost:7001/rest/getBook/5 + "?_" +new Date()
Since each time URL is different, It does not refer to browser cache.
由于每次 URL 不同,它不指浏览器缓存。
回答by Oleksandr Kelepko
You can use POSTs instead of GETs. POSTs are not cached.
您可以使用 POST 而不是 GET。POST 不会被缓存。