寻求用户关闭浏览器/标签页时调用API的可靠方案(含React相关)
现代浏览器对unload事件中的异步请求有严格限制,容易被中断,而navigator.sendBeacon()是浏览器专门为页面卸载时发送请求设计的API,它会将请求加入后台发送队列,保证页面卸载过程中请求能完成发送,不会被浏览器取消。
原生JavaScript实现
// 监听beforeunload事件(触发于窗口/标签关闭、刷新前) window.addEventListener('beforeunload', (event) => { // 可选:触发浏览器的关闭确认提示(如需拦截误操作可保留,不需要则删除) event.preventDefault(); event.returnValue = ''; // 构造请求数据(支持FormData、Blob、字符串等格式) const requestData = new FormData(); requestData.append('userId', '你的用户ID'); requestData.append('action', 'session_terminated'); // 发送API请求 if (navigator.sendBeacon) { // 优先使用sendBeacon navigator.sendBeacon('/your-api-endpoint', requestData); } else { // 兼容旧浏览器的降级方案(同步XHR,会阻塞页面卸载,仅作备选) const xhr = new XMLHttpRequest(); xhr.open('POST', '/your-api-endpoint', false); xhr.send(requestData); } });
React组件中实现
import { useEffect } from 'react'; function YourComponent() { useEffect(() => { const handlePageUnload = (event) => { // 可选:触发关闭确认提示 event.preventDefault(); event.returnValue = ''; const requestData = new FormData(); requestData.append('userId', '你的用户ID'); requestData.append('action', 'session_terminated'); if (navigator.sendBeacon) { navigator.sendBeacon('/your-api-endpoint', requestData); } }; // 添加事件监听 window.addEventListener('beforeunload', handlePageUnload); // 组件卸载时移除监听 return () => { window.removeEventListener('beforeunload', handlePageUnload); }; }, []); return <div>你的组件内容</div>; } export default YourComponent;
进阶:带自定义请求头的场景
如果API需要自定义请求头(如Content-Type: application/json),可以使用fetch并开启keepalive选项:
window.addEventListener('pagehide', async () => { const payload = JSON.stringify({ userId: '你的用户ID', action: 'session_terminated' }); await fetch('/your-api-endpoint', { method: 'POST', headers: { 'Content-Type': 'application/json', }, body: payload, keepalive: true // 关键:启用keepalive保证请求完成 }); });
注意事项
sendBeacon仅支持POST请求,无法自定义请求头,适合简单表单或字符串数据传输- 避免使用
unload事件,优先选择beforeunload或pagehide作为触发时机 - 同步XHR会阻塞页面卸载流程,影响用户体验,仅作为老旧浏览器的降级方案
- 后端需确保能正确解析
sendBeacon或keepalive请求的数据格式(如FormData或JSON)
内容的提问来源于stack exchange,提问作者Shahzad Siddique
相关产品推荐
相关产品推荐

