工作中遇到一个需求,需要在用户关闭或者刷新页面时向后端发送该用户的身份信息。
浏览器页面卸载时会触发beforeunload和unload事件,由于unload限制比较多,因此这里选择了beforeunload。
问题:常用的异步ajax请求在unload/beforeunload事件内是不可靠的,浏览器可能会无视异步请求从而导致后端收不到。可以使用下述方法。
1. 同步ajax
window.addEventListener('beforeunload', () => {
const url = 'test.com';
const params = { test : 'test' };
$.ajax({
type: 'POST',
url: url,
data: params,
async: false
});
});
同步ajax会阻断浏览器的unload,直到ajax环节结束后才会继续进行unload。
此方法的缺点是由于页面会在ajax请求结束后才延迟卸载,会导致关闭时浏览器出现卡顿降低用户的体验。
注意:chrome不支持在页面关闭事件内使用同步XMLHttpRequest请求
Disallow sync XHR in page dismissal - Chrome Platform Status
2. beacon
window.addEventListener('beforeunload', () => {
const url = 'test.com';
const params = { test : 'test' };
navigator.sendBeacon(url, JSON.stringfy(params));
});
beacon api设计就是用来解决页面卸载时发送请求的问题。他能保证在页面unload完成前请求能够被发送,并且由于其是异步且非阻塞的,并不会影响浏览器其他页面的显示效率。
sendBeacon只能发送http post请求。
问题:此方法无法自定义header信息,如果服务端设置了token权限拦截,sendBeacon并没有办法将token信息放入请求中。
3. fetch
window.addEventListener('beforeunload', () => {
const url = 'test.com';
const params = { test : 'test' };
const headers = new Headers();
headers.append('content-type', 'application/json');
headers.append('token', 'token');
fetch(url, {
method: 'POST',
headers: headers,
body: JSON.stringify(params),
// 重要!!!
keepalive: true,
});
});
fetch方法配合参数中的keepalive字段会让浏览器在页面卸载后在后台继续接管网络请求,该字段是必须的。
此方法的缺陷为keepalive字段一次只能承载最大64KB的请求内容,且该限制是所有并行请求共享的,即,页面卸载阶段所有fetch+keepalive请求的内容体总和不能超过64KB。
参考文章
Sending AJAX Data when User Moves Away / Exits from Page