页面卸载前(用户关闭页面)向服务器发送请求
废话不说,直接进正题。
最近项目有个需求需要在用户关闭页面时将页面存留的统计数据发送到后端。该需求有两个关键点:
- 监听页面卸载
- 在卸载时发送数据
如何监听用户关闭页面
首先我们需要明确,哪些场景属于用户关闭页面:
- 关闭浏览器
- 关闭/刷新页面
可监听上述场景的API为:
- unload
- beforeunload
- pagehide
- visibilitychange
但在许多情况下(尤其是移动设备)浏览器不会产生 unload、beforeunload 或 pagehide 事件。下面列出了一种不触发上述事件的情况:
- 用户加载了网页并与其交互。
- 完成浏览后,用户切换到了其它应用程序,而不是关闭选项卡。
- 随后,用户通过手机的应用管理器关闭了浏览器应用。
故此,我们采用visibilitychange + pagehide的组合方式监听用户行为。
if((typeof document.onvisibilitychange) !== 'undefined') {
document.addEventListener('visibilitychange', function logData() {
if (document.visibilityState === 'hidden') {
// ... 发送数据
}
});
}else if((typeof window.onpagehide) !== 'undefined') {
window.addEventListener("pagehide", event => {
if (event.persisted) {
/* the page isn't being discarded, so it can be reused later */
}
}, false);
}
如何在卸载时发送数据
方法一: window.navigator.sendBeacon
语法
navigator.sendBeacon(url, data);
参数:
-
url:表明 data 将要被发送到的网络地址。
-
data(可选): 将要发送的 ArrayBuffer、ArrayBufferView、Blob、DOMString、FormData 或 URLSearchParams 类型的数据。
返回值:当成功将数据加入传输队列返回true
,否则返回false
。
示例
const blob = new Blob([JSON.stringify(data)], { type: 'application/json; charset=UTF-8'});
window.sendBeacon(url, blob);
其他
- 数据限制:在大多浏览器上最多只能发送64kb的数据(亲测Chrome及Safari浏览器上最多发送64kb)。
- 请求方法:通过POST请求发送数据。
- 请求头: 通过传入数据data自动设置请求头,一般的: FormData: multipart/form-data,DomString: text/plain ,想传递json数据到后端,可以通过Blob对象间接达到设置Content-type的效果。
浏览器兼容
方法二: fetch设置keepalive为true
语法
Promise
fetch(input[, init]);
参数详见:fetch()-MDN
示例
fetch(url, {
body: data,
mode: 'no-cors',
method: 'POST',
headers: { 'Content-Type': 'application/json'}
}).then(response => response.json())
.then(data => console.log(data));
其他
- 数据限制:设置keepalive为true,最多只能发送64kb的数据(亲测Chrome及Safari浏览器上最多发送64kb)。
浏览器兼容
参考
- fetch()-MDN
- Navigator.sendBeacon()-MDN
- visibilitychange-MDN
- Window: 页面隐藏事件 (pagehide event)
- Navigator.sendBeacon() data size limits
- When fetch is used keepalive is the default, and Chrome only allows a POST body <= 65536 bytes in that scenario
- 监听用户关闭浏览器、离开浏览器事件
- 深度好文: 从js visibilitychange Safari下无效说开去
- fetch协议
- Beacon标准