History.js 能否通过 pushState 跨 HTTP 和 HTTPS?
结论
不能。history.pushState() 只能写入与当前页面同源的 URL。HTTP 和 HTTPS 属于不同源,即使域名和端口相同,协议不同也会触发浏览器的安全限制。
因此,在下面的 HTTP 页面中:
http://www.example.com/some/resource
不能直接执行:
history.pushState(
null,
null,
'https://www.example.com/payment/for/some/resource'
);
History.js 无法绕过这项限制,传入完整 URL 也不会改变结果。
原因
浏览器通过以下三个部分判断两个地址是否同源:
- 协议(scheme)
- 主机名(host)
- 端口(port)
下面两个地址使用了不同的协议,所以不属于同一个源:
http://www.example.com
https://www.example.com
pushState() 只会修改当前文档的历史记录和地址栏,并不会加载另一个页面。浏览器不允许 HTTP 文档借此把地址栏伪装成 HTTPS 页面,否则用户可能误以为当前内容已通过安全连接加载。
完整 URL 并非不能使用,但它必须与当前页面同源。例如,当前页面本身也位于相同的 HTTPS 源时,可以执行:
history.pushState(
null,
null,
'https://www.example.com/payment/for/some/resource'
);
推荐方案:真正跳转到 HTTPS
进入支付页面时,应使用普通页面导航:
window.location.assign(
'https://www.example.com/payment/for/some/resource'
);
也可以直接赋值:
window.location.href =
'https://www.example.com/payment/for/some/resource';
浏览器会重新加载页面并建立真正的 HTTPS 连接。支付完成或退出支付流程后,再按业务需要导航到其他页面。
如果希望继续使用 AJAX 页面加载
可以让整个移动站点都运行在 HTTPS 下。这样,普通页面与支付页面属于同一个源,AJAX、History API 和页面切换动画仍可继续使用。
例如,当前页面是:
https://www.example.com/some/resource
此时可以先通过 AJAX 获取同源的支付页面,再更新历史记录:
const paymentUrl =
'https://www.example.com/payment/for/some/resource';
$.ajax({
url: paymentUrl,
method: 'GET'
}).done(function (html) {
$('#page-container').html(html);
history.pushState(
{ page: 'payment' },
'',
paymentUrl
);
});
同时还要处理浏览器的前进和后退操作:
window.addEventListener('popstate', function (event) {
loadPage(window.location.href, {
pushHistory: false
});
});
pushState() 本身不会发起请求。页面内容加载、错误处理和界面更新仍由 AJAX 加载器负责。
如果暂时不能全站启用 HTTPS
可以把支付入口当作跨源边界。用户点击支付链接时,停止 AJAX 页面切换,改用完整跳转:
$(document).on('click', 'a.payment-link', function (event) {
event.preventDefault();
window.location.assign(this.href);
});
不要先通过 AJAX 获取 HTTPS 支付页面,再从 HTTP 页面调用 pushState()。即使服务器配置了 CORS,它也只能控制网络请求权限,无法解除 History API 的同源限制。
注意事项
- History.js 只是对浏览器历史功能的封装,不能改变原生 History API 的安全规则。
- 无论指定绝对 URL、相对 URL,还是更换 History.js 的调用方式,都无法通过
pushState()从 HTTP 切换到 HTTPS。 - 支付页面必须通过真正的 HTTPS 导航打开,不能只修改地址栏来表示连接已经安全。
- 如果全站使用 HTTPS,应将 HTTP 请求重定向到对应的 HTTPS 地址,避免用户停留在不安全页面。
- 支付流程还要正确处理会话 Cookie,通常应根据实际需求配置
Secure、HttpOnly和SameSite属性。 - 不建议将支付表单或敏感支付数据作为普通 AJAX 页面片段注入 HTTP 页面。只要外层文档仍是 HTTP,整个交互就不具备 HTTPS 页面应有的安全保障。
备注:内容仅供参考。
