阅读 473

如何在web页面关闭或刷新之前,发送Ajax到服务端

最近在做实时视频这块的封装,需要客户端Ajax实时上报状态给服务端,以确认用户的当前的通话状态。这个时候,涉及到当用户离开客户端时候(关闭浏览器),发送离线状态给服务器。

一、监听浏览器关闭事件

浏览器关闭事件会有两个,unload 和 **beforunload,两者是有区别的,从字面上来看,beforunload的调用是在 unload之前。

1、beforeunload在用户即将离开页面时触发,它返回一个字符串,浏览器会向用户展示并询问这个字符串以确定是否离开。

2、unload在用户已经离开时触发,我们在这个阶段仅可以做一些没有延迟的操作,由于种种限制,很少被使用。

3、需要注意的是,如果在两个事件监听中添加 alert、confirm、prompt会忽略

4、生效情况:

  • 1·关闭浏览器窗口
  • 2·通过地址栏或收藏夹前往其他页面的时候
  • 3·点击返回,前进,刷新,主页其中一个的时候
  • 4·点击 一个前往其他页面的url连接的时候
  • 5·调用以下任意一个事件的时候:click,document.write()方法(输出内容),document.open() 打开一个新的空白文档,document.close()方法可关闭一个由open()方法打开的输出流,并显示选定的数据。 ,window close (),form.submit.
  • 6·当用window open打开一个页面,并把本页的window的名字传给要打开的页面的时候。
  • 7·重新赋予location.href的值的时候。
  • 8·通过input type=”submit”按钮提交一个具有指定action的表单的时候。
  • 9.可以用在以下元素:body, frameset, window

==上代码==

window.onunload = function(){
	// 相关代码
}
window.onbeforeunload = function(){
    // 相关代码
}
window.addEventListener('unload', ()=>{
    // 相关代码
});
window.addEventListener('beforeunload', ()=>{
    // 相关代码
});
复制代码

有时候两个监听需要配合使用,当然,避免重复调用,要做一些处理。

二、发送请求

有了上面两个监听为前提下,我们来关心一下怎么能把请求发送成功给服务端。如果只是在监听中随便写个请求,说不定请求还没发出去,已经被浏览器停止了,异步的Ajax不一定能准确的到达服务端。下面有三个想法可以进行实现。

1、请求设置为同步(不建议)

大家第一反应可能是,把请求设置为同步请求,上代码:

var xml = new XMLHttpRequest();

xml.open('POST', url , false); // false表示不是异步请求

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

xml.onreadystatechange = function() {
    if (xml.readyState == 4 && xml.status == 200) {
        var responeData = xml.responseText;
        var data = JSON.parse(responeData);
    } else {
        // 处理异常
    }
};

xml.send('account=1&password=123456');

复制代码

这种方法可以实现,但是对用户体验会有比较大的影响,并且在http协议最新的提案中,有考虑剔除请求同步标准

2、使用navigator中的sendBeacon发送异步请求(建议)

相关使用方法

body = JSON.stringify(body);
// 原来是 xhr.send(body)变为
navigator.sendBeacon(url,body);

复制代码

支持发送的body可以是ArrayBufferView, Blob, DOMString, 或者 FormData 类型的数据。 根据MDN的介绍:

主要用于满足 统计和诊断代码的需要,这些代码通常尝试在卸载(unload)文档之前向web服务器发送数据。过早的发送数据可能导致错过收集数据的机会。然而, 对于开发者来说保证在文档卸载期间发送数据一直是一个困难。因为用户代理通常会忽略在卸载事件处理器中产生的异步 XMLHttpRequest 。

复制代码

下面介绍一下两种其他不同类型的发送方式

  • (1) body使用Blob对象,有个好处是,可以自定义的设置header
blob = new Blob([`accoutn=12332323`], {type : 'application/x-www-form-urlencoded'});
navigator.sendBeacon("/leave", blob);

复制代码
  • (2) 使用FormData对象,但是这时content-type会被自动变成"multipart/form-data"
var fd = new FormData();
fd.append('account', 123);
navigator.sendBeacon("/leave", fd);
复制代码

3、服务端实现接收

=-=结束语:通过以上两种结合,可以在页面结束时候,进行Ajax请求的发送=-=

原文参考相关链接:juejin.im/post/5c7e54…

关注下面的标签,发现更多相似文章
评论