有个需求,我们需要在用户发送数据过程中,如果用户关闭了网页(包括整个浏览器关闭),不要中断数据传递
目前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技巧_脚本之家