Web页面关闭时发送Ajax请求的几种方案及sendBeacon用法

作者:阿沐

时间:2026-10-22

浏览:151

本文详解在用户关闭或离开Web页面时发送数据上报的多种实现方式。对比了同步Ajax、服务端忽略Abort以及推荐的navigator.sendBeacon异步方案,重点解析sendBeacon的使用方法及Blob、FormData等数据格式的处理技巧,解决页面卸载时请求被中断的问题。

文章目录

Web页面关闭时发送Ajax请求的几种方案及sendBeacon用法

前言

在某些业务场景下,我们需要在用户离开当前页面时执行数据上报以记录用户行为,或者通过Ajax请求通知服务器用户已离开,例如直播间内的退房操作。

本文将分两部分详细讲解如何实现退出行为的数据上报。

页面关闭事件监听机制

1. 事件监听机制

浏览器提供了两个关键事件用于监听页面关闭行为:beforeunload和unload。

beforeunload事件在文档和资源即将关闭时触发,此时文档仍可见,且该事件可被取消。例如,若采用如下代码写法,用户刷新或关闭页面时会弹出确认框,询问是否关闭页面。


window.addEventListener("beforeunload", function (event) {
 // Cancel the event as stated by the standard.
 event.preventDefault();
 // Chrome requires returnValue to be set.
 event.returnValue = '';
});

unload事件则在页面开始卸载时发生。此时文档状态表现为:1. 所有资源(如图片、iframe等)依然存在;2. 用户对资源不可见;3. 界面交互失效(window.open、alert、confirm等方法不可用);4. 错误不会阻止文档的卸载过程。

基于上述两个事件,我们可以实现对页面关闭的监听。为确保稳妥,建议同时监听这两个事件,并对监听函数进行封装,确保关闭逻辑仅执行一次。

页面卸载时的请求发送策略

2. 请求发送策略

仅完成事件监听是不够的。如果在监听函数中直接发送标准的Ajax请求,会发现请求会被浏览器强制中止(abort),导致无法成功发送。因为在页面卸载阶段,浏览器无法保证异步请求能够顺利完成。

针对这一问题,我们有以下几种解决方案:

方案一:发送同步Ajax请求


var oAjax = new XMLHttpRequest();

oAjax.open('POST', url + '/user/register', false);//false表示同步请求

oAjax.setRequestHeader("Content-type", "application/x-www-form-urlencoded");

oAjax.onreadystatechange = function() {
 if (oAjax.readyState == 4 && oAjax.status == 200) {
 var data = JSON.parse(oAjax.responseText);
 } else {
 console.log(oAjax);
 }
};

oAjax.send('a=1&b=2');

该方法虽然有效,但用户必须等待请求结束才能关闭页面,严重影响用户体验。

方案二:发送异步请求,并在服务端忽略Ajax的中止(abort)

尽管异步请求会被浏览器中止,但如果服务端能够忽略中止操作并继续执行,则方案可行。例如,PHP提供了ignore_user_abort函数来处理此类情况。但这需要修改后台代码,通常实施成本较高,可行性较低。

方案三:使用navigator.sendBeacon发送异步请求

根据MDN文档介绍:

该方法主要满足统计和诊断代码的需求,这些代码通常尝试在文档卸载前向Web服务器发送数据。过早发送数据可能导致数据收集遗漏。然而,对开发者而言,保证在文档卸载期间发送数据一直是一个难点,因为用户代理通常会忽略在卸载事件处理器中产生的异步XMLHttpRequest。

从上述介绍可以看出,sendBeacon正是为解决用户离开时发送请求的场景而设计,非常适合此类需求。

其基本使用方式如下:


navigator.sendBeacon(url [, data]);

sendBeacon支持发送的数据类型包括ArrayBufferView、Blob、DOMString或FormData。

以下是几种使用sendBeacon发送请求的方式。我们可以修改Header和内容格式,但由于与服务器的通信协议通常固定,若随意修改Header或内容格式,服务器可能无法正确识别。

(1)使用Blob发送数据

使用Blob发送的优势在于可以自定义内容格式和Header。例如,通过以下设置方式,可将content-type设置为application/x-www-form-urlencoded。


blob = new Blob([`room_id=123`], {type : 'application/x-www-form-urlencoded'});
navigator.sendBeacon("/cgi-bin/leave_room", blob);

Web页面关闭时发送Ajax请求的几种方案及sendBeacon用法

(2)使用FormData对象,此时content-type会自动设置为"multipart/form-data"。


var fd = new FormData();
fd.append('room_id', 123);
navigator.sendBeacon("/cgi-bin/leave_room", fd);

Web页面关闭时发送Ajax请求的几种方案及sendBeacon用法

(3)数据也可以使用URLSearchParams对象,此时content-type会被设置为"text/plain;charset=UTF-8"。


var params = new URLSearchParams({ room_id: 123 })
navigator.sendBeacon("/cgi-bin/leave_room", params);

Web页面关闭时发送Ajax请求的几种方案及sendBeacon用法

经测试发现,使用Blob发送较为便捷,内容设置也更具灵活性。若发送的消息经抓包后发现后台未识别,可尝试修改内容的字符串格式或Header,以找到合适的发送方式。 参考链接:

  • sendBeacon API not working temporarily due to security issue, any workaround?
  • Sending AJAX Data when User Moves Away / Exits from Page
  • Setting HTTP Headers in a Beacon Request

总结

以上就是本文的全部内容,希望本文的内容对大家的学习或者工作具有一定的参考学习价值,如果有疑问大家可以留言交流,谢谢大家对本站的支持。

实用工具推荐

电子包浆

绿化、压缩、噪点和虚拟水印,自由调节做旧程度。

使用 ›
图片压缩

选择画质和输出格式,预览压缩前后的大小。

使用 ›
相关文章