首页 > 解决方案 > history.pushState URL 与 jquery 加载的交互导致页面获取失败?

问题描述

我正在使用history.pushState来设置 URL,同时使用 jquery .load来实际加载页面内容。我是历史 API 的新手,但我知道这是在动态站点中获取后退按钮/等功能的正常方式。

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

  1. 当用户点击链接 1 时,服务器应该返回dir1/dir2/p1.html #Container1,并且地址栏应该显示foo.com/a/b/c
  2. 当用户点击链接 2 时,服务器应该返回dir1/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

我一直在尝试并找到两种方法来解决这个问题,但我真的不明白发生了什么,所以我不会发布这个作为答案:

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

标签: javascriptjqueryajaxhtml5-history

解决方案


更改历史状态将更改文档的URL,因此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

作为面向 StackSnippet 的 null 起源 iframe 限制的用户的 jsfiddle

或者,您甚至可以只在您的文档中从第一个页面加载开始将此 <base> 元素附加一次。


推荐阅读