AJAX 页面 load/history.pushState 在离开网站后无法正常工作

AJAX page load/history.pushState not working properly after navigating off website

我的网站使用 XMLHttpRequests 在用户单击 link 时请求部分网页。

相关代码:

function requestPage(url, push) {
    var xhr = new XMLHttpRequest();
    xhr.onreadystatechange = function () {
        if (xhr.readyState === 4) {
            main.innerHTML = xhr.responseText;
            attachLinkClickHandlers(main); // `main` = container element

            if (push)
                window.history.pushState(url, title, url);
        }
    };

    xhr.open('GET', url);
    xhr.setRequestHeader('Content-Only', 1); // Server responds to Content-Only header by not sending everything surrounding the main content.
    xhr.send();
}

window.addEventListener('popstate', function (e) {
    var page = e.state;
    requestPage(page, false);
});

window.history.replaceState(location.href, document.title, location.href);
attachLinkClickHandlers(document);

在 link 上点击:

requestPage(link.href, true);

服务器响应示例:

正常请求响应:

<!doctype html>
<html>
    <head>
        ...stuff...
    </head>
    <body>
        ...stuff...
        <main>
            <h1>Content</h1>
            <p>Content Content</p>
        </main>
        ...stuff...
    </body>
</html>

响应 Content-Only header 设置:

<h1>Content</h1>
<p>Content Content</p>

一切正常(页面加载,back/forward 按钮导航 站点内), 除了 ... 如果我点击一个 external link(没有附加点击处理程序,因为那将是跨源的)然后按下浏览器上的后退按钮,我是迎接 XHR 的响应 - 只是内容,没有 <html><head><body> 标签,这意味着没有 CSS 或 JavaScript要么。

发生这种情况时如何让浏览器加载完整页面?

您是否使用相同的 URL 来检索两种不同类型的内容?

如果是这样,我遇到了完全相同的问题。我使用相同的 URL 和不同的请求 headers 到 return html 应用程序页面或一些 JSON 数据。在 history.pushState 调用和导航离开后,单击返回将导致 JSON 响应显示在浏览器中(因为这是与 URL 关联的浏览器缓存的最后响应)。

浏览器似乎只跟踪 URL 及其响应。使用 XHR 请求 headers 来指定您真正想要的内容类型是浏览器不会跟踪的。因此,当您离开然后 return 时,浏览器所拥有的只是 URL (可能还有缓存的响应)。

我的解决方法是改变 URLs,它实际上从那些用于修改浏览器历史记录的数据中获取 JSON 数据。

// on click of product item 123
var url = 'http://<webserver>/products/123',
    title = 'Product 123';

history.pushState({
        url: url,
        title: title
    }, title, url);

product = $.getJSON(url + '?json=1'); // make the url different

我整理了一些小测试来强调它是如何工作的https://github.com/robbishop/history-api-test

我已经在一些浏览器中尝试过,并注意到 Firefox(50.0 版)的工作方式与 Chrome 不同。例如,如果您修改页面内容,然后用假的 URL 调用 history.pushState,然后导航离开,然后单击返回。在 Chrome 中,您会得到一个 404 页面未找到(因为 URL 不是真实的),但在 Firefox 中,它实际上恢复了您上次看到的页面。所以浏览器也有一些差异,但我认为在直接操作浏览器历史记录

时,将 URLs 与单一内容类型相关联可能更安全