页面关闭(前/时/后)将统计数据发送到 Web 服务器的方案:
一、XMLHttpRequest
缺点:定时器(setInterval)间隔时间不好把握,Ajax 也会浪费大量的资源。
setInterval(() => {
$.ajax({
type: "method",
url: "url",
data: "data",
dataType: "dataType",
success: function (response) {
}
});
}, interval);
二、beforeunload
当浏览器窗口关闭或者刷新时,会触发 beforeunload 事件。当前页面不会直接关闭,可以点击确定按钮关闭或刷新,也可以取消关闭或刷新。
window.addEventListener('beforeunload', function (event) {
// Cancel the event as stated by the standard.
event.preventDefault();
// Chrome requires returnValue to be set.
event.returnValue = '';
});
三、unload
当文档或一个子资源正在被卸载时, 触发 unload 事件。
window.addEventListener('unload', function(event) {
console.log('unload');
});
方案二和方案三的缺点:
- 无法获取用户取消/确认的回调
- 无法区分刷新/关闭
四、websocket
双方发送数据很及时。若客户端离线,服务器端马上就知道了。
但若只是个小项目,感觉有点重了。
五、img元素
创建一个 img 元素并设置 src
,但是大部分浏览器会延迟卸载(unload)文档以加载图像。
六、Beacon【推荐】
特点:
- 通过 HTTP POST 将少量数据(<64 KB)异步传输,可靠性好
- 这个请求不需要响应,保证在页面的 unload 状态从发起到完成之前被发送。
- 不会阻塞页面卸载,也就不会影响下一导航的载入
- 支持跨域
- 不支持自定义请求头
语法:
navigator.sendBeacon(url);
navigator.sendBeacon(url, data);
示例1:
window.addEventListener('unload', function (event) {
const data = {name: "beacon"};
navigator.sendBeacon('/log', JSON.stringify(data));
});
示例2:
document.addEventListener('visibilitychange', function logData() {
if (document.visibilityState === 'hidden') {
navigator.sendBeacon('/log', analyticsData);
}
});
七、Fetch keep-alive
keepalive
属性用于页面卸载时,告诉浏览器在后台保持连接,继续发送数据。带有 keepalive
标志的 Fetch 是 Navigator.sendBeacon() API
的替代品。
同样典型的场景就是用户离开网页时,向服务器提交一些用户的行为统计数据。
开启了 keepalive
属性后,网页就算被关闭了,请求被会继续执行而不会中断。
示例:
window.onunload = function() {
fetch('/analytics', {
method: 'POST',
body: "statistics",
keepalive: true
});
};
相比 Beacon API
,他有这么一些好处:能自定义请求头,不仅仅局限于 POST 请求…
总之只是在 Fetch 添加了一个 keepalive 属性,所以就把他当作一个正常的 Fetch 请求使用就行。