spring 如何正确防止缓存302重定向位置?

zujrkrfu  于 2023-04-28  发布在  Spring
关注(0)|答案(5)|浏览(171)

我遇到的下一个问题是 Post/Redirect/Get 模式。重定向后执行GET时,Chrome会从缓存中获取页面。因此用户看到陈旧的数据。

我已尝试跟踪以强制/支持重新验证

if (request.checkNotModified(sinceLastTweet)) return null;
response.setHeader("Cache-Control", "no-cache");
response.setHeader("Last-Modified", String.valueOf(sinceLastTweet));

但只有no-store会导致服务器请求。
为什么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";
}
gc0ot86w

gc0ot86w1#

1)你必须尝试强制Chrome不使用该高速缓存,
How to control web page caching, across all browsers?
就像这个问题的答案建议你必须把这个头放在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)你可以搞点小把戏
您可以通过编程来使用相同的控制器响应以下格式的任何请求:

http://localhost:8080/spitter/username-{timestamp}

然后,您可以更改页面中的链接,使其具有发送请求之前的最后一个时间戳。
在这种情况下,如果chrome缓存页面的事件没有关系。
除了时间戳,你可以使用任何其他方法,比如“autoincrement”或“uuid”。

bakd9h0s

bakd9h0s2#

如果一个Chrome示例缓存了页面/username,则该页面不会被该Chrome重定向,因为Chrome读取Location头并提供缓存的页面。
也许有一次你在尝试缓存头部时访问了页面,现在你的Chrome认为它必须缓存它,甚至可能永远。
您需要使/username页面该高速缓存无效(使用该Chrome):
1.将/username页面设置为总是提供禁用缓存的头文件,就像rev_dihazum建议的那样,或者Spring WebContentGenerator中如何完成的那样。
1.手动清除该高速缓存或访问/username并在页面中按CTRL+R:如果实际请求的是一个页面,则将读取缓存禁用标头,并且从那时起,每次都会再次向服务器请求该页面,包括由于重定向而请求时。
如果页面是公共的,并且用户(其浏览器无法控制)已经缓存了它,那么问题就更糟了,您可以选择以下选项之一:
1.等待缓存过期
1.更改页面名称
1.向Location URL添加一些随机数,或多或少如prad121所建议的,以使其唯一,2)
请注意,Last-Modified时间格式为Tue, 15 Nov 1994 08:12:31 GMT,您可以使用setDateHeader方法将其设置为long
您可以查看WebContentGenerator以查看Spring中的其他缓存代码。

atmip9wb

atmip9wb3#

在URL的末尾添加一些随机数(当前时间,单位为毫秒)。像服务URL是

http://localhost:7001/rest/getBook/5

因此,在进行上述服务调用时,您在末尾添加一些随机数,而不是调用上述URL

/rest/getBook/5?_time-in-milisec

它需要在javascript中对服务调用进行少量调整。

URL = http://localhost:7001/rest/getBook/5 + "?_" +new Date()

由于每次URL是不同的,它不涉及浏览器缓存.

pbpqsu0x

pbpqsu0x4#

也许你可以尝试在你的页面上使用ETag。
我不确定我是否正确理解了你的重定向场景。
假设你有一些显示页面包含一个username,你有一些第二个页面为你的数据提供编辑,你希望能够改变username,然后按一个按钮保存它,然后回到显示页面。
一种选择是在URL中包含username(如...&username=Jack)。由于用户名已更改,因此URL也会更改(即。即...&username=Jim)。在这种情况下,Chrome不会有Jack显示页面的缓存版本,而是会从服务器获取它的新版本。(如果你有任何字段不想在URL中显式提及,你可以计算所有字段的校验和,并将其作为一个参数添加,如...&check=12345678)。
另一种选择是让服务器生成一个ETag -所以让我们来详细研究一下。我们想要的是,服务器应用程序负责告诉浏览器数据是否需要刷新或可以从该高速缓存中获取,对吗?

  • {请原谅我在这里没有使用你的例子,因为我目前正在不同的Stack上开发-但是,我认为你的问题可以用Java/Spring Stack以同样的方式解决}*

看一下Response Headers一节的截图,中间你会看到ETag。这个id是由服务器生成的-所以服务器应用程序在这里控制。(如果你还没有实现ETag,也许这个article可以帮助你。)
那会发生什么?* 一旦服务器上的内容发生变化,ETag也会发生变化-* 浏览器 * 在响应中看到ETag,尊重服务器的负责,并询问服务器内容是否发生变化,如果是,则踢出缓存的过期内容页面并向服务器请求新页面。
当然,你必须确保,一旦服务器得知用户从 Jack 更改为 Jim(或相应的任何其他字段),服务器应用程序就会为该用户的显示页面生成新的ETag。
希望有帮助!

mqxuamgl

mqxuamgl5#

您可以使用POST而不是GET。POST不缓存。

相关问题