有个需求,我们需要在用户发送数据过程中,如果用户关闭了网页(包括整个浏览器关闭),不要中断数据传递
目前XMLHttpRequest对象是不支持的
http服务器
为了测试效果我们用nodejs写了个http服务器代码 文件名为httpServer.js如下,执行node httpServer.js就可以跑起来,支持get,post携带数据
// 导入http模块
const http = require('http');
var querystring = require('querystring');
// 创建Web服务器对象
const server = http.createServer();
// 监听端口号5005并启动HTTP服务器
server.listen(5005, () => {
    console.log('Web服务器启动成功啦!')
})
// 服务器实例通过.on()方法为服务器绑定request事件,监听客户端发来的请求,触发事件处理函数
server.on('request', (req, res) => {
    const version = req.httpVersion;
    const url = req.url;
    const method = req.method;
    console.log("收到请求:" + url + "method:" + method)
    res.setHeader('Content-Type', 'application/json');
    res.setHeader("Access-Control-Allow-Origin", '*')
    let info = { url: url, method: method }
    if (method.toLocaleLowerCase() == "post") {
        // 定义了一个post变量,用于暂存请求体的信息
        var post = '';
        // 通过req的data事件监听函数,每当接受到请求体的数据,就累加到post变量中
        req.on('data', function (chunk) {
            post += chunk;
        });
        // 在end事件触发后,通过querystring.parse将post解析为真正的POST请求格式,然后向客户端返回。
        req.on('end', function () {
            post = JSON.parse(post);
            info.body = post;
            console.log("post", post)
            // 调用res.end()方法向客户端响应一些内容
            res.end(JSON.stringify(info));
        });
    }
    else {
        // 调用res.end()方法向客户端响应一些内容
        res.end(JSON.stringify(info));
    }
})终端效果
如果服务器收到网络请求,你的cmd或终端会看到如下的信息

我们写了三个网络请求函数
XMLHttpRequest请求
 function ajaxFn() {
            return new Promise((resolve, reject) => {
                var request = new XMLHttpRequest();
                request.open('get', request_url);
                request.send();
                request.onreadystatechange = function () {
                    if (request.readyState == 4) {
                        // console.log(request.responseText)
                        // console.log("ajax响应内容", request.responseText)
                        resolve(JSON.parse(request.responseText))
                    }
                }
                request.onerror = function (e) {
                    console.error("ajax跨域")
                    reject(2)
                }
            })
        }调用方式
//XMLHttpRequest关闭窗口后不会发起网络请求
            ajaxFn().then(res=>{
                console.log("ajax响应内容",res)
            })fetch请求 &&调用
//fetch 开启keepalive,可以发起网络请求,且不局限类型
            fetch(request_url, {
                method: 'post',
                keepalive: true,
                body: JSON.stringify({
                    'name': 'lili'
                })
            }).then(response => {
                response.json().then((data) => {
                    console.log("fetch响应内容",data);
                    return data;
                }).catch((err) => {
                    console.log(err);
                })
            })navigator.sendBeacon发送数据
  navigator.sendBeacon(request_url, JSON.stringify({ name: "sendBeacon" }), true);为什么这里叫发送数据了,因为它不提供响应数据的回调函数,目标就是使用发送数据,只要服务器接口存在,关闭浏览器都不会影响继续发送数据
写个按钮,点击时候分不触发上面的函数,结果都可以发送数据
改为页面即将销毁时候触发上面函数
window.addEventListener('unload', function (event) {
            //触发函数
        });结果XMLHttpRequest方式请求数据的方式,后台无法接受到数据
移动端兼容
unload事件在移动端上面不支持可以做以下判断
if (window.onunload) {
            window.addEventListener('unload', function (event) {
                //........
            });
        }
        else{
            document.addEventListener('visibilitychange', function logData() {
            if (document.visibilityState === 'hidden') {
                ///.....
            }
        });
 }结论
使用navigator.sendBeacon场景:
- 传递少量数据
- 不考虑响应结果
- 只要求post请求方式
- 浏览器窗口关闭依旧发送数据
- 不会阻塞页面卸载,也就不会影响下一导航的载入
- 支持跨域(不关心数据响应,也没有跨域的顾虑,跨域是可以发送数据的,只是没法读取响应数据)
- 不支持自定义请求头
使用fetch keepalive
- 不考虑传递数据体积大小
- 大多数时候需要响应数据结果
- 任意请求方式
- 浏览器窗口关闭依旧发送数据&&不考虑响应结果
XMLHttpRequest
 浏览器关闭后,不需要发送数据
 
 
 
 
参考
Navigator.sendBeacon() - Web API 接口参考 | MDN
Navigator sendBeacon页面关闭也能发送请求方法示例_javascript技巧_脚本之家


















