带有部分页面加载的HTML5 History API后退按钮

时间:2012-06-28 09:01:26

标签: html5 http-headers browser-cache pushstate popstate

为了提高我网站的性能/响应能力,我使用AJAX,replaceState,pushState和popstate监听器实现了部分页面加载。

我基本上将页面的中心部分(HTML)存储为历史记录中的状态对象。单击链接时,我只从服务器请求页面的中心位(用不同的Accept标识标识这些请求)并用javascript替换它。在popstate上,我抓住前面的中央部分并将其推回到dom中。

这大部分工作正常,但是我发现了一个我坚持的特殊问题。解释起来有点复杂,所以如果不是很清楚我会道歉。

我们的大部分网页都有搜索表单。通过ajax加载部分页面仅在GET请求上,并且表单执行POST,导致整页加载。

如果我浏览下面的一组页面,我最终会出现一个格式错误的部分页面,其中包含 ONLY 中心内容,没有任何周围的dom:

从主页开始(通过整页加载) - 执行搜索(重定向后获取) 带您进入搜索结果(通过整页加载) - 然后单击主页
返回主页(通过动态获取) - 单击浏览器返回
搜索结果(来自popstate listener) - 单击浏览器返回
格式错误的主页。

当出现格式错误的主页时,我的popstate监听器根本不存在。

我认为正在发生的事情是,浏览器正在缓存主页的第二次加载(动态,部分),然后当完整页面返回时,浏览器仅仅是显示缓存的部分响应而不是整页。

为了解决这个问题,我在响应中添加了一个Vary:Accept标头,让浏览器知道内容可能会根据accept标头发生变化。我还为部分加载的内容添加了Cache-Control max-age = 0,pragma no-cache和过去的到期日期,以试图强制浏览器不缓存它,但这些都没有解决它。

不幸的是,我的公司不允许外部流量到我们的开发服务器,因此我无法向您展示问题。我在这里看过各种类似的问题,但它们似乎都不一样,所提出的解决方案似乎也不起作用。

如果我向动态GET请求添加一个无意义的参数(blah = blah),这就解决了这个问题。然而,这是一个丑陋的黑客,我宁愿不做。这似乎应该可以解决标题,因为我认为这是一个缓存问题。谁能解释一下发生了什么?

3 个答案:

答案 0 :(得分:9)

这是一个缓存问题。将响应标头Cache-Control设置为no-cachemax-age=0,问题不会发生在FF中(正如您所说),但它仍然存在于Chrome中。

适合我的标题是Cache-Control:no-store。所有浏览器都没有始终如一地实现这一点(您可以找到问题,询问无缓存和无存储之间的区别),但是您也可以在Chrome中获得结果。

答案 1 :(得分:1)

我有类似的问题。我正在构建一个基于Web的向导,并使用jquery ajax加载每个步骤(后端的ASP.NET MVC)。

初始路线类似于/ Questions / Show - 它会加载整个页面并显示第一个问题(问题0)。当用户单击Next图像时,它会使用url / Questions / Save / 0执行jquery .load()。这样可以保存答案并返回包含下一个问题的局部视图。下一次保存使用/ Questions / Save / 1 ...

进行jquery .load()

我实现了History.js,以便用户可以前进(前进?)。它将问题编号存储在状态数据中。当它检测到状态改变(并且状态的问题编号与页面上的问题编号不同)时,它会执行jquery .load()来加载正确的问题。

起初我使用与加载初始页面时相同的路径(/ Questions / Show / X,其中X是问题编号)。在后端,我检测到它是否是ajax请求,如果是,则返回部分视图而不是完整视图。这就是与你的问题类似的问题:说我问题3,回去,然后转发,然后转到www.google.com,然后点击后退按钮。它显示了问题3,但它是部分视图 - 因为浏览器缓存了该路径的部分内容。

我的解决方案是为ajax调用创建一个单独的路由:/ Questions / Load / X(它在后端使用公共代码)。现在有两条不同的路线(/ ajax的问题​​/显示和/ ajax的/ Questions / Load),浏览器在上述情况下正确显示整页。

所以也许一个类似的解决方案对你有用......即你的主页有两个不同的路线 - 一个用于整页,一个用于部分。希望有所帮助。

答案 2 :(得分:1)

  

点击链接时,我只是从服务器请求页面的中心位(使用不同的Accept标识标识这些请求)并将其替换为javascript。

真棒。这是RESTful方式。但要做到这一点还有一件事要做:在响应中添加Vary标题。

Vary: Accept

告诉浏览器具有不同Accept标头的请求可能会得到不同的响应。由于这两个请求使用不同的Accept标头,因此浏览器(以及任何缓存代理)将单独缓存响应。

与设置Cache-Control: no-store不同,这仍然允许您使用缓存。