admin管理员组文章数量:1529446
业务场景
当用户关闭浏览器、刷新浏览器或者跳转其他页面时,向服务器发送一些统计数据。
常规方案
1. 直接发送 xhr 请求
我们会优先想到监听页面的unload
或者beforeunload
事件,在事件回调里使用XMLHttpRequest
发送异步请求。
但是由于是xhr
请求是异步发送,很可能在它即将发送的时候,页面已经卸载了,从而导致发送取消或者发送失败。异步请求响应返回后,由于页面和相关资源已经卸载,会引起function not found
的错误。
解决方法就是 AJAX 通信改成同步发送,即只有发送完成,页面才能卸载。
const syncReport = (url, { data = {}, headers = {} } = {}) => {
const xhr = new XMLHttpRequest();
xhr.open('POST', url, false);
xhr.withCredentials = true;
Object.keys(headers).forEach((key) => {
xhr.setRequestHeader(key, headers[key]);
});
xhr.send(JSON.stringify(data));
};
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
将xhr
请求改为同步,虽然能够完成发送数据,但存在以下两个问题:
- 部分浏览器已经不支持同步的 XMLHttpRequest 对象了(即open()方法的第三个参数为false);
xhr
请求改为同步后,会阻塞页面的卸载和跳转,导致下一个页面导航加载的时机变晚,用户体验较差。
2. 动态图片
通过在unload
事件处理器中,创建一个图片元素并设置它的 src 属性的方法来延迟卸载以保证数据的发送。因为绝大多数浏览器会延迟卸载以保证图片的载入,所以数据可以在卸载事件中发送。
const reportData = (url, data) => {
let img = document.createElement('img');
const params = [];
Object.keys(data).forEach((key) => {
params.push(`${key}=${encodeURIComponent(data[key])}`);
});
img.onload = () => img = null;
img.src = `${url}?${params.join('&')}`;
};
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
这种方法存在同样的问题,页面卸载流程被阻塞,后面页面的加载时机被延迟,用户体验不好
Navigator.sendBeacon
浏览器引入的sendBeacon
方法,**发出的是异步请求,但是请求是作为浏览器任务执行的,与当前页面是脱钩的。**因此该方法不会阻塞页面卸载流程和延迟后面页面的加载。
1. 基本用法
navigator.sendBeacon(url, data);
url 就是上报地址,data 可以是 ArrayBufferView
,Blob
,DOMString
或 Formdata
,根据官方规范,需要 request header 为 CORS-safelisted-request-header,在这里则需要保证 Content-Type
为以下三种之一:
application/x-www-form-urlencoded
multipart/form-data
text/plain
我们一般会用到 DOMString
, Blob
和 Formdata
这三种对象作为数据发送到后端,下面以这三种方式为例进行说明。
// 1. DOMString类型,该请求会自动设置请求头的 Content-Type 为 text/plain
const reportData = (url, data) => {
navigator.sendBeacon(url, data);
};
版权声明:本文标题:刷新或关闭浏览器时,向后台提交数据 内容由热心网友自发贡献,该文观点仅代表作者本人, 转载请联系作者并注明出处:https://m.elefans.com/xitong/1726626409a1078808.html, 本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容,一经查实,本站将立刻删除。
发表评论