关闭、刷新页面时发送请求的方式
关闭、刷新时,即页面卸载时,正常的ajax请求都会被取消掉,所以需要特殊的方式,才能保证请求成功发送。
-
同步的xhr请求
xhrReq.open(method, url, false);
有人已经实现了对应的封装:beforeunload-request,可以查看下源码:大致方式就是按上述三种方式以及顺序依次尝试。
NOTE: 在使用
beforeonloadRequest
函数时,应该自行保证contentType
的类型和数据的类型保持一致,参考Content-Type详解,比如
contentType
为application/json
时,数据对象应该使用JSON.stringify()
处理;contentType
为application/x-www-form-urlencoded
时,数据应改为a=1&b=2&c%5Ba%5D=1&c%5Bb%5D=2
格式,可用Qs.stringify()
处理。
NOTE: 实测过程中,ios设备下关闭页面和刷新页面时,前端打印显示
sendbeacon
成功发送,但是就是后端就是没有接收日志。所以在上述情况下,本文的方案有问题。
关闭、刷新页面发送请求的时机
不同浏览器、不同系统、不同终端(pc、移动),对于页面生命周期的实现、页面卸载时触发的事件都不一样,sendbeacon里有提到相关问题。想要精准的覆盖所有情况很有难度,所以监听了关闭、刷新页面时所有可能触发的事件,然后加上锁,防止重复上报。
// 防止重复上报
let isTriggerUnloadReport = false
window.onbeforeunload = () => {
unloadReport()
};
window.onpagehide = () => {
unloadReport()
};
window.onunload = () => {
unloadReport()
};
// NOTE:当然在各种页面不可见得情况下也会触发,比如浏览器窗口被完全覆盖、当前浏览器tab页被切换、mac切窗口
document.onvisibilitychange = () => {
if (document.visibilityState === 'hidden') {
unloadReport()
} else {
isTriggerUnloadReport = false;
}
};
function unloadReport () {
if (isTriggerUnloadReport) {
return;
}
isTriggerUnloadReport = true;
beforeonloadRequest(`/report`, {
method: 'POST',
headers: {
'Content-Type': 'application/json; charset=UTF-8',
},
body: JSON.stringify({id: 1}),
});
};