当前位置:网站首页>页面关闭前,如何发送一个可靠请求
页面关闭前,如何发送一个可靠请求
2022-07-04 22:17:00 【swlws9527】

一、问题
从 A 页面进入到 B 页面前,向后台发送一个/log请求,如何保证这个请求一定会被接收并处理。
场景复现
function nextPage() {
fetch("/log", {
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify({
some: "data",
}),
});
window.location.href = "/other.html";
}
这段代码里,页面切换成功后,后台是接收不到/log请求的。原因:
- js 的执行可以认为分为
主线程、异步线程 - 当页面进入
terminated状态时,会释放所有的资源。也就是说,此时异步线程中未执行的上下文,不会再被处理。
二、解决方案
2.1 async/await
既然是因为异步导致的请求被执行,那改为同步即可。
async function nextPage() {
await fetch("/log", {
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify({
some: "data",
}),
});
window.location.href = "/other.html";
}
这种方式会阻塞代码执行
2.2 keepAlive
fetch中设置keepalive为true时,即使发起请求的页面处于terminated状态,也会保持连接。利用这哥特性,可以发送可靠的请求。
function nextPage() {
fetch("/log", {
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify({
some: "data",
}),
keepalive: true,
});
window.location.href = "/other.html";
}
2.3 navigator.sendBeacon
使用 sendBeacon() 方法会使用户代理在有机会时异步地向服务器发送数据,同时不会延迟页面的卸载或影响下一导航的载入性能,这意味着:
- 数据发送是可靠的。
- 数据异步传输。
- 不影响下一导航的载入。
代码示例:
function nextPage() {
navigator.sendBeacon(
"/log",
JSON.stringify({
some: "data",
})
);
window.location.href = "/other.html";
}
sendBeacon()API 不支持添加请求头,可以利用Blob做一些改动支持请求头
function nextPage() {
const blob = new Blob([JSON.stringify({
some: "data" })], {
type: "application/json; charset=UTF-8",
});
navigator.sendBeacon("/log", blob);
window.location.href = "/other.html";
}
需要注意的是,在Chrome的network面板下,它的文档类型为ping,不是常见的fetch、xhr类型。
2.4 <a>标签的 ping 属性
越来越多的厂商支持ping属性了。示例:
<a href="/other.html" ping="/log">other page</a>
点击a标签时,会额外发送一个请求/log,它的请求头中包含几个特殊的值:
{
"ping-from": "http://127.0.0.1:3000/",
"ping-to": "http://127.0.0.1:3000/other.html",
"content-type": "text/ping"
}
三、方案选择
如果出现以下情况,可以使用 fetch()+keepalive:
- 需要自定义请求头。
- 使用 GET 请求,不是 POST 请求。
- 支持较旧的浏览器(如 IE),并且已经加载了 fetch polyfill。
但如果满足以下条件,sendBeacon()可能是更好的选择:
- 进行简单的服务请求,不需要太多定制化。
- 更喜欢更干净、更优雅的 API。
- 希望保证您的请求不会与应用程序中发送的其他高优先级请求竞争。
参考:
边栏推荐
- Common open source codeless testing tools
- Concurrent optimization summary
- 面试必备 LeetCode 链表算法题汇总,全程干货!
- Mysql root 账号如何重置密码
- 记录:关于Win10系统中Microsoft Edge上的网页如何滚动截屏?
- 【lua】int64的支持
- 通过Go语言创建CA与签发证书
- 虚拟人产业面临的挑战
- About stack area, heap area, global area, text constant area and program code area
- 【愚公系列】2022年7月 Go教学课程 003-IDE的安装和基本使用
猜你喜欢

嵌入式开发:技巧和窍门——提高嵌入式软件代码质量的7个技巧

NFT Insider #64:电商巨头eBay提交NFT相关商标申请,毕马威将在Web3和元宇宙中投入3000万美元

With this PDF, we finally got offers from eight major manufacturers, including Alibaba, bytek and Baidu

BigFilter全局交易防重组件的介绍与应用

Energy momentum: how to achieve carbon neutralization in the power industry?

Embedded development: skills and tricks -- seven skills to improve the quality of embedded software code

将QA引入软件开发生命周期是工程师要遵循的最佳实践

TLA+ 入门教程(1):形式化方法简介

达梦数据凭什么被称为国产数据库“第一股”?

Convolutional neural network model -- lenet network structure and code implementation
随机推荐
面试必备 LeetCode 链表算法题汇总,全程干货!
Energy momentum: how to achieve carbon neutralization in the power industry?
力扣_回文数
将QA引入软件开发生命周期是工程师要遵循的最佳实践
SQL中MAX与GREATEST的区别
2022-07-04:以下go语言代码输出什么?A:true;B:false;C:编译错误。 package main import “fmt“ func main() { fmt.Pri
The Sandbox 和数字好莱坞达成合作,通过人力资源开发加速创作者经济的发展
SPSS安装激活教程(包含网盘链接)
我在linux里面 通过调用odspcmd 查询数据库信息 怎么静默输出 就是只输出值 不要这个
Solana chain application crema was shut down due to hacker attacks
Convolutional neural network model -- lenet network structure and code implementation
PostgreSQL服务端编程聚合和分组
都说软件测试很简单有手就行,但为何仍有这么多劝退的?
Force buckle 2_ 1480. Dynamic sum of one-dimensional array
业务太忙,真的是没时间搞自动化理由吗?
The table is backed up in ODPs. Why check m in the metabase_ Table, the logical sizes of the two tables are inconsistent, but the number of
9 - 类
LOGO特訓營 第三節 首字母創意手法
sobel过滤器
2022-07-04: what is the output of the following go language code? A:true; B:false; C: Compilation error. package main import “fmt“ func main() { fmt.Pri