美文网首页收藏
Navigator.sendBeacon-页面关闭也能发送请求

Navigator.sendBeacon-页面关闭也能发送请求

作者: 涅槃快乐是金 | 来源:发表于2022-04-04 23:21 被阅读0次

背景


最近在需求中有一个这样的场景:需要在页面关闭的时候,用户不需要操作,主动关闭当前订单
当时考虑的方案:在页面关闭的时候,向后端发送一个请求,将这个资源释放掉;
定下方案时,觉得也不是什么难事,觉得谷歌浏览器应该会提供页面关闭的 API 供开发者使用。
经过查找,找到了这么两个 API :beforeunloadunload

beforeunload

当浏览器窗口关闭或者刷新时,会触发 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

当文档或一个子资源正在被卸载时, 触发 unload 事件。

unload 事件在 beforeunload 事件后触发,这时候文档处于一个什么状态呢?
所有资源都存在,像图片,iframe的等,但是这些资源对于用户来说均不可见,界面上的交互也是无效的.
使用方式和 beforeunload 相同,但是 unload 事件中不能使用确认框,毕竟都已经在卸载了

window.addEventListener('unload', function(event) {
  console.log('unload');
});

问题

  • 用户无论刷新还是关闭了页面,因为这两种操作都会调用beforeunloadunload
  • 异步请求会被 cancel 掉,导致请求无法发送成功,由于使用的axios进行请求,浏览器有几率关闭异步请求,造成请求无法发出,可以尝试换成同步。
    在事件的回调中使用同步的 AJAX 请求。
window.addEventListener('unload', function (event) {
  let xhr = new XMLHttpRequest();
  xhr.open('post', '/log', false);
  xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
  xhr.send('foo=bar');
});

但是谷歌浏览器已经不允许页面关闭期间进行同步的 XMLHTTPRequest(),这条规则适用于 beforeunloadunloadpagehidevisibilitychange这些 API;
为了确保页面在卸载时讲数据发送到服务器,官方建议使用 sendBeacon()或者 Fetch keep-alive

Navigator.sendBeacon

这个方法主要用于满足统计和诊断代码的需要,这些代码通常尝试在卸载(unload)文档之前向web服务器发送数据。
Beacon API 有以下这样几个特点:

  • 通过 HTTP POST 将少量数据异步传输,可靠性好
  • 这个请求不需要响应,保证在页面的 unload 状态从发起到完成之前被发送。
  • 不会阻塞页面卸载,也就不会影响下一导航的载入
  • 支持跨域
  • 不支持自定义请求头
    用法如下:
navigator.sendBeacon(url, data);

url 就是上报地址,data 可以是 ArrayBufferViewBlobDOMStringFormdata,根据官方规范,需要 request header 为 CORS-safelisted-request-header,在这里则需要保证 Content-Type 为以下三种之一:

  • application/x-www-form-urlencoded
  • multipart/form-data
  • text/plain

我们一般会用到 DOMString , BlobFormdata 这三种对象作为数据发送到后端,下面以这三种方式为例进行说明。

  • DOMString

如果数据类型是 string,则可以直接上报,此时该请求会自动设置请求头的 Content-Typetext/plain

const reportData = (url, data) => {
  navigator.sendBeacon(url, data);
};

  • Blob

如果用 Blob 发送数据,这时需要我们手动设置 Blob 的 MIME type,一般设置为 application/x-www-form-urlencoded

const reportData = (url, data) => {
  const blob = new Blob([JSON.stringify(data), {
    type: 'application/x-www-form-urlencoded',
  }]);
  navigator.sendBeacon(url, blob);
};

  • Formdata

可以直接创建一个新的 Formdata,此时该请求会自动设置请求头的 Content-Typemultipart/form-data

const reportData = (url, data) => {
  const formData = new FormData();
  Object.keys(data).forEach((key) => {
    let value = data[key];
    if (typeof value !== 'string') {
      // formData只能append string 或 Blob
      value = JSON.stringify(value);
    }
    formData.append(key, value);
  });
  navigator.sendBeacon(url, formData);
};

注意这里的 JSON.stringify 操作,服务端需要将数据进行 parse 才能得到正确的数据。

Fetch keep-alive

当使用fetch() 方法时,如果把keeplive 设置为true,即便页面被终止请求也会保持连接。

window.onunload = function() {
  fetch('/analytics', {
    method: 'POST',
    body: "statistics",
    keepalive: true
  });
};

相关文章

  • Navigator.sendBeacon-页面关闭也能发送请求

    背景 最近在需求中有一个这样的场景:需要在页面关闭的时候,用户不需要操作,主动关闭当前订单当时考虑的方案:在页面关...

  • AJAX

    发请求的方式 ,但是会刷新页面或者新开页面 ,可以发送get请求,也会刷新页面或者新开页面 ,可以发送get请求,...

  • 关闭页面时发送请求失败的解决办法

    项目需求是在页面关闭时要发送一个请求到后台。于是就监听beforeunload事件,在回调中发送请求。 内网测试一...

  • AJAX

    1. 如何发送请求 通过form表单发送请求(包括get请求和post请求),会刷新页面或新开页面 通过a链接发送...

  • 从地址栏输入URL到页面加载显示的过程分析

    DNS域名解析 TCP建立连接 发送HTTP请求 服务器处理请求返回HTTP报文 浏览器解析渲染页面 关闭连接 总...

  • ajax:asynchronous javascript and

    如何发送请求 1,form可以发送请求,但是将导致刷新页面或者新开页面2,a标签可以发送get请求,同样将导致刷新...

  • Navigator.sendBeacon 无阻塞发送统计数据

    场景:前端埋点,网页刷新或者关闭的时候调用异步请求 常规方案 直接发送 xhr 请求我们会优先想到监听页面的unl...

  • 前端全(无)埋点之页面停留时长统计

    当前页面关闭统计方案 当前页面关闭统计方案解的思路就是阻塞页面关闭,先发数据统计请求,然后再关闭页面 1 解决方案...

  • AJAX是什么?

    历史上发送请求的方式 用 form 可以发请求,但是会刷新页面或新开页面 用 a 可以发 get 请求,但是也会刷...

  • 如何在 Web 关闭页面时发送 Ajax 请求

    有时候我们需要在用户离开页面的时候,做一些上报来记录用户行为。又或者是发送服务器ajax请求,通知服务器用户已经离...

网友评论

    本文标题:Navigator.sendBeacon-页面关闭也能发送请求

    本文链接:https://www.haomeiwen.com/subject/cuuhsrtx.html