使用 navigator.sendBeacon
实现高效的数据上报
在 web 开发中,我们经常需要将用户行为或性能数据上报到服务器。为了不影响用户体验,开发者通常会在页面卸载时进行数据上报。然而,传统的数据上报方式,如 XMLHttpRequest
或 Fetch API
,容易受到页面卸载过程中的阻塞,导致数据丢失。为了解决这个问题,navigator.sendBeacon
API 被引入,它可以在页面卸载时安全、可靠地发送数据。
navigator.sendBeacon
对比 Ajax fetch
优点
- 不受页面卸载过程的影响,确保数据可靠发送。
- 异步执行,不阻塞页面关闭或跳转。
- 能够发送跨域请求。
缺点
- fetch 和 ajax 都可以发送任意请求 而 sendBeacon 只能发送POST
- fetch 和 ajax 可以传输任意字节数据 而 sendBeacon 只能传送少量数据(64KB 以内)
- fetch 和 ajax 可以定义任意请求头 而 sendBeacon 无法自定义请求头
- sendBeacon 只能传输
ArrayBuffer
、ArrayBufferView
、Blob
、DOMString
、FormData
或URLSearchParams
类型的数据 如果处于危险的网络环境,或者开启了广告屏蔽插件 此请求将无效
navigator.sendBeacon
应用场景
- 发送心跳包:可以使用
navigator.sendBeacon
发送心跳包,以保持与服务器的长连接,避免因为长时间没有网络请求而导致连接被关闭。 - 埋点:可以使用
navigator.sendBeacon
在页面关闭或卸载时记录用户在线时间,pv uv,以及错误日志上报 按钮点击次数。 - 发送用户反馈:可以使用
navigator.sendBeacon
发送用户反馈信息,如用户意见、bug 报告等,以便进行产品优化和改进
其他注意事项 type
ping请求 是html5 新增的 并且是sendBeacon 特有的 ping 请求 只能携带少量数据,并且不需要等待服务端响应,因此非常适合做埋点统计,以及日志统计相关功能。
demo用法
<button class="send">发送</button>
const send = document.querySelector('.send')
send.addEventListener('click', () => {
let data = JSON.stringify({name:'test'})
const blob = new Blob([data], { type: 'application/json' })
navigator.sendBeacon('http://localhost:3000/api/beacon',blob,{
type:"beacon"
})
})
nodejs
import express from 'express';
const app = express();
app.post('/api/beacon', (req: any, res) => {
console.log(req.body);
res.send('ok');
});
app.listen(3000, () => {
console.log('Listening on port 3000');
});