谷歌浏览器按返回按钮时显示ajax响应

54

我遇到了一个问题,如果我使用 jQuery 的 Get 方法获取一些内容,如果我点击返回按钮,它并不会实际上回到历史记录中的上一页,而是显示 Ajax 查询返回的内容。

有什么想法吗?

http://www.dameallans.co.uk/preview/allanian-society/news/56/Allanian-test

在上面的页面中,如果您使用评论列表下方的分页功能,在更改页面后单击返回按钮,您会注意到它显示用于生成评论列表的 HTML 内容。

我注意到它并不总是这样做,但如果您多次单击不同的页码并单击返回按钮,则会在窗口内简单地显示 json 文本,而不是网站。

出于某种原因,这只会影响 Chrome 浏览器,而 IE 和 Firefox 则工作正常。


2
你有找到解决这个问题的方法吗?我也遇到了相同的问题。 - gabe
9个回答

47

3
我已经为这个 bug 愁了好几个星期了。谢谢! - 3urdoch
21
快速解决方法:在 ajax 请求的 URL 后添加“?ajax=true”。 - Ben Miller
答案实际上应该是“确保URL未被缓存”,其中一个解决方案可能是使用不同的URL... - webjunkie
我不太理解这个问题。一方面是因为缓存,另一方面它又不使用缓存。如果它使用了缓存,就不会生成新的响应。我的应用程序为Ajax和非Ajax显示不同的响应,在返回时,Chrome显示这个Ajax响应。这意味着它不使用缓存。这太荒谬了,缓存怎么可能与Ajax有关系? - Robo Robok

21

实际上,这是缓存系统根据规范的预期行为,而不是Chrome的问题。缓存仅基于URL和请求方法(GET、POST等)区分请求,不考虑任何请求头。

但是有一个Vary头告诉浏览器在检查缓存时考虑一些头部信息。例如,在服务器响应中添加Vary:X-Requested-With会告诉浏览器此响应因请求中的X-Requested-With头部发生更改而变化。或通过在服务器响应中添加Vary:Content-Type告诉浏览器此响应因请求中的Content-Type头部发生更改而变化。

您可以将此行代码添加到PHP路由器中:

header('Vary:X-Requested-With');

在 Node.js 中使用中间件:

app.use(function(req, res) {
    res.header('Vary', 'X-Requested-With');
});

对我来说可以。我必须在ajax和从url栏中获取的经典收入中使用相同的url。我使用的Ajax库没有cache=false... - AntiCZ
5
这实际上是最优雅的答案。谢谢! - webjunkie

21

如果你正在使用History API(或类似history.js的库)和jQuery,那么应该将$.getJSON更改为带有缓存设置为false的$.ajax:

$.ajax({
    dataType: "json",
    url: url,
    cache: false,
    success: function (json) {...}
});

cache: false选项的作用是在URL后附加时间戳,因此如果您使用jQuery,则它是最佳解决方案。它仅适用于HEAD和GET请求,并在dataTypescriptjsonp时自动设置。 - tombeynon

6
您还可以在ajax url的末尾添加一个随机值。这将忽略以前的Chrome缓存,并请求新版本。
url = '/?'+Math.random()

5
只需将以下标题添加到响应头即可:Response headers:
Vary: Accept

1

在2021年使用Chrome仍然存在此问题。

问题在于执行基本的ajax请求到与用户当前所在页面相同的url。 我正在使用Symfony,对我有效的完整解决方案是:

$response->headers->addCacheControlDirective('no-cache', true);
$response->headers->addCacheControlDirective('max-age', 0);
$response->headers->addCacheControlDirective('s-maxage', 0);
$response->headers->addCacheControlDirective('must-revalidate', true);
$response->headers->addCacheControlDirective('no-store', true);

/**
 * from https://dev59.com/53I-5IYBdhLWcg3wMFS0#1975677
 *
 * The HTTP request header 'Accept' defines the Content-Types a client can process.
 * If you have two copies of the same content at the same URL, differing only in Content-Type,
 * then using Vary: Accept could be appropriate.
 */
$response->headers->set('Vary', 'Accept');

1

由于这是ajax分页,无法为每个ajax请求提供不同的url。在标头上声明无缓存没有任何作用,因此当标头是针对ajax请求时,我在视图中包含了一些小的javascript代码:

<script>
if (typeof jQuery == 'undefined') {
    window.location = "<?php echo $this->here; ?>";
}
</script>

这是一个不太光彩的技巧,但它有效。如果ajax内容通常被加载,那么容器已经加载了Jquery,所以它不会做任何事情。但是,如果你加载没有周围内容的ajax内容,Jquery就会丢失(至少在我的情况下),所以我重定向到当前页面,请求一个带有所有头和脚本的正常GET页面。
如果将其放在页面顶部,用户不会注意到,因为它不会等待页面加载,只要浏览器获取这4行就会重定向...
在你的应用程序中替换这里;?>为当前的URL,这是一个CakePhp 2.X。

0

@abraham的答案是正确的。 我只是想为Rails发布一个解决方案:你只需要在routes.rb中添加不同的路径。

例如,我有resource :people,我想从ajax部分组成索引页面,其中之一是人员列表。直接的方法是创建index.js.erb并通过使用url: people_path的ajax加载部分。但这里出现了问题。

因此,对于Rails,它只需要添加不同的路由,如下所示:

get 'people_list', to: 'people#index', as: :people_list, format: :js


0
如果我想在Laravel控制器中使用索引方法返回HTML和JSON响应,我需要在端点的末尾添加一个GET参数来传递浏览器缓存。
axios.get(url, {params: {ajax: 1}})

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接