history.pushState URL 与 jquery 加载的交互导致页面获取失败?

history.pushState URL interaction with jquery load causing page fetch failure?

我正在使用 history.pushState to set a URL, while at the same time using a jquery .load 实际加载页面内容。我是历史新手 API,但我知道这是在动态站点中获得 back-button/etc 功能的正常方法。

问题是我用 pushState 设置的欺骗地址被 .load 在获取页面时以某种方式使用,这意味着 .load 正试图获取不存在的页面,因此失败。 DocumentRoot 在服务器上 /var/www/bar。在此示例中,用户试图在服务器上的单个 html 文件中的两个点之间导航,该文件位于服务器上 DocumentRoot 下的 dir1/dir2/p1.html

  1. 当用户点击link1时,服务器应该returndir1/dir2/p1.html #Container1,地址栏应该显示foo.com/a/b/c
  2. 当用户点击link2时,服务器应该returndir1/dir2/p1.html #Container2,地址栏应该显示foo.com/a/b/d

那我该怎么做呢?这是我尝试使用相对 URL 的方法,但失败了:

$("#mainContent").load("dir1/dir2/p1.html #container1");  // good: XHR fetch foo.com/bar/dir1/dir2/p1.html
history.pushState(null, null, "a/b/c");                   // good: shows 'foo.com/a/b/c' as the URL
...
$("#mainContent").load("dir1/dir2/p1.html #container2");  // bad: XHR fetch foo.com/bar/a/b/dir1/dir2/p1.html
history.pushState(null, null, "a/b/d");                   // bad: shows 'foo.com/a/b/a/b/d' as the URL

这就是我使用绝对 URL 时发生的情况:

$("#mainContent").load("/dir1/dir2/p1.html #container1");  // good: XHR fetch foo.com/bar/dir1/dir2/p1.html
history.pushState(null, null, "a/b/c");                    // good: shows 'foo.com/a/b/c' as the URL
...
$("#mainContent").load("/dir1/dir2/p1.html #container2");  // bad: XHR fetch foo.com/a/b/dir1/dir2/p1.html
history.pushState(null, null, "a/b/d");                    // good: shows 'foo.com/a/b/d' as the URL

请注意,绝对路径甚至更糟,因为 XHR 提取甚至不再使用 DocumentRoot (bar)。谢谢。

编辑 1

相对案例在 Chrome/Windows 和 Firefox/Linux 上测试,结果相同;绝对案例仅在 Firefox/Linux.

上测试

编辑 2

我一直在试验并找到了两种解决此问题的方法,但我不太明白发生了什么,所以我不会post将此作为答案:

  1. history 设置的所有 URL 保持一级深度,因此 a/b/c 变为 a-b-c。我在历史上用谷歌搜索过的所有内容 API 只显示一级深度 URL,所以这可能很常见
  2. base 标签添加到网站的 <head> (<base "href=http://example.com/" target="_blank">

改变历史状态 will change the document's URL and thus its baseURI 如果没有其他东西已经改变它,比如 <base> 元素。

所以所有未来的网络请求确实会从这个新的基本 URI 发出。

要解决此问题,您可以在更改历史记录状态后手动设置 baseURI,

console.log( document.baseURI ); // /js

history.pushState(null, null, '/foo');
console.log( document.baseURI ); // /foo

// manually set document's baseURI via <base>
const base = document.createElement('base');
base.href = 'bar';
document.head.append(base);
console.log( document.baseURI ); // /bar

As a jsfiddle for users facing StackSnippet's null origined iframes restrictions

或者您甚至可以从第一页加载开始在您的文档中仅附加一次此 元素。