2
头图

JS Navigator.sendBeacon 可靠的、异步地向服务器发送数据

前言

我们在上一篇页面访问&页面关闭数据上报的文章中使用了 sendBeacon 方法用来发送数据,上篇文章是简单使用,那本篇文章我们就详细了解下这个东西。

一、Navigator.sendBeacon 是什么&能做什么?

Navigator.sendBeacon 是一个用于发送少量数据到服务器的 API,尤其适用于在页面即将卸载时发送数据,如日志记录、用户行为分析等。

与传统的 AJAX 请求不同,sendBeacon 方法的设计目标是确保数据在页面卸载(例如用户关闭标签页或导航到新页面)时能够可靠地发送。

Navigator.sendBeacon 方法可用于通过 HTTP POST 将少量数据异步传输到 Web 服务器。

它主要用于将统计数据发送到 Web 服务器,同时避免了用传统技术(如:XMLHttpRequest)发送分析数据的一些问题。

所以上篇文章在页面关闭进行数据上报的时候,我们就选择了 navigator.sendBeacon 方法。

二、Navigator.sendBeacon 详细介绍

1、使用场景

  1. 页面卸载时的日志记录:在用户离开页面时记录行为数据,如页面停留时间、点击行为等。
  2. 分析和监控:发送用户行为数据到分析服务器,用于网站性能监控和用户行为分析。
  3. 状态报告:向服务器报告应用程序状态或错误信息。

2、不使用 Navigator.sendBeacon 时,如何处理?

  1. 发起一个同步 XMLHttpRequest 来发送数据(open() 方法的第三个参数为 false)。
  2. 创建一个 <img> 元素并设置 src,大部分用户代理会延迟卸载(unload)文档以加载图像。
  3. 创建一个几秒的 no-op 循环。

3、不使用 Navigator.sendBeacon 可能会带来哪些问题?

3.1. 同步 XHR
  1. 同步请求会阻塞浏览器的主线程,导致页面在请求完成之前无法响应用户操作。这会严重影响用户体验,尤其是在请求需要较长时间才能完成时。
  2. 许多现代浏览器会对同步请求发出警告,提示开发者这种方法可能会导致性能问题,并建议改用异步请求。
3.2. 创建 img 元素
  1. 页面卸载流程被阻塞。
  2. 后面页面的加载时机被延迟,用户体验不好。
3.3. 创建循环
  1. 页面卸载流程被阻塞。
  2. 后面页面的加载时机被延迟,用户体验不好。

4、Navigator.sendBeacon 的优点

  1. 可靠性:sendBeacon 的主要设计目标是确保数据在页面卸载时能够可靠地发送。浏览器会在后台继续尝试发送数据,即使页面已经关闭或正在导航到新页面。
  2. 非阻塞:sendBeacon 方法是非阻塞的,不会阻碍页面的卸载过程。相比于传统的同步 AJAX 请求,不会影响用户体验或导致页面卸载延迟。
  3. 简单性:接口简单,只需提供目标 URL 和数据,无需处理响应。适用于只需要发送数据而不需要从服务器获取数据的场景。
  4. 安全性:与其他 AJAX 请求方法一样,sendBeacon 遵循同源策略,不能发送跨域请求,除非服务器设置了适当的 CORS 头。

5、使用限制

  1. 数据大小限制(通常为几十 KB),适用于发送少量数据。
  2. 因为数据大小有限,sendBeacon 不适合用于发送大量或大文件的数据。
  3. sendBeacon 方法始终使用 HTTP POST 请求。
  4. 不返回响应,不提供处理服务器响应的机制,无法检查请求是否成功以及服务器的返回结果。

6、浏览器兼容性

Navigator.sendBeacon 支持主流的现代浏览器,包括 ChromeFirefoxSafariEdge 等,但不支持较老的浏览器(如 IE 11 及更早版本)。

image

三、Navigator.sendBeacon 如何使用

1、语法

navigator.sendBeacon(url);
navigator.sendBeacon(url, data);

2、参数

2.1. url

url 参数表明 data 将要被发送到的网络地址。

2.2. data 可选

data 参数是将要发送的 ArrayBufferArrayBufferViewBlobDOMStringFormDataURLSearchParams 类型的数据。

3、返回值

类型:boolean

当用户代理成功把数据加入传输队列时,sendBeacon() 方法将会返回 true,否则返回 false

4、Navigator.sendBeacon 使用举例

4.1. 参数格式为 ArrayBuffer

适用于传递二进制数据,如文件或图像片段。

const buffer = new ArrayBuffer(8);
navigator.sendBeacon('/log', buffer);
4.2. 参数格式为 ArrayBufferView

ArrayBufferView 是一种表示二进制数据视图的类型。常见的 ArrayBufferView 类型包括 Uint8Array, Int8Array, Uint16Array, Int16Array, Uint32Array, Int32Array, Float32Array, Float64Array 等等。

// 创建一个包含字符串的 Uint8Array
const text = 'Hello, world!';
const textEncoder = new TextEncoder();
const textArray = textEncoder.encode(text); // 将字符串编码为 Uint8Array
// 创建一个包含其他二进制数据的 Uint8Array
const binaryData = new Uint8Array([1, 2, 3, 4, 5]);
// 将两部分数据合并到一个大的 Uint8Array
const combinedArray = new Uint8Array(textArray.length + binaryData.length);
combinedArray.set(textArray, 0);
combinedArray.set(binaryData, textArray.length);
// 发送合并后的 Uint8Array
navigator.sendBeacon('xxx/xxx', combinedArray);
4.3. 参数格式为 Blob

适用于传递文件或其他大块的二进制数据。

const blob = new Blob(['user=gqk'], { type: 'text/plain' });
navigator.sendBeacon('xxx/xxx', blob);
4.4. 参数格式为 DOMString

适用于简单的文本数据。

navigator.sendBeacon('xxx/xxx', 'this is sendBeacon case');
4.5. 参数格式为 FormData

适用于发送表单内容或复杂的键值对数据。

const formData = new FormData();
formData.append('user', 'gqk');
navigator.sendBeacon('xxx/xxx', formData);
4.6. 参数格式为 URLSearchParams

适用于发送 URL 编码的查询参数。

const params = new URLSearchParams();
params.append('user', 'gqk');
navigator.sendBeacon('xxx/xxx', params);

四、Navigator.sendBeacon 和 XHR、fetch 有什么异同点

1、相同点

  1. 发送网络请求:所有这三种方法都用于从客户端向服务器发送数据。
  2. 支持多种数据格式:它们都可以发送字符串、JSON、二进制数据等多种格式的数据。

2、不同点

2.1. Navigator.sendBeacon
  1. 用于在页面卸载时发送少量数据,适合日志、分析数据等用途。
  2. 发送数据是异步的,但不返回任何信息给调用者,无法处理服务器的响应。
  3. 设计为在页面卸载时保证数据发送,即使在浏览器关闭或页面跳转时。
  4. 始终使用 HTTP POST 请求。
  5. 不需要处理响应,使用简单。
2.2. XMLHttpRequest
  1. 用于更复杂的、需要处理响应的 AJAX 请求。
  2. 可以进行同步或异步请求。
  3. 可以处理服务器的响应,并进行进一步处理(如解析 JSON、处理状态码等)。
  4. 提供丰富的事件(如 onloadonerroronprogress 等),可以监控请求的各个阶段。
  5. 在所有主流浏览器中都得到了广泛支持,包括一些较老的浏览器。
  6. 使用较复杂,需要处理请求的各个阶段和状态。
2.3. Fetch
  1. 现代化的请求接口,用于替代 XMLHttpRequest,支持更简单和更灵活的请求和响应处理。
  2. 始终进行异步请求,返回 Promise 对象。
  3. 支持链式处理响应,可以轻松解析 JSON、处理状态码等。
  4. 支持 async/await 语法,更符合现代 JavaScript 开发习惯。
  5. 更好地支持跨域请求和 CORS(跨域资源共享)。
  6. 允许在请求中添加更多的选项(如自定义头部、请求方法等)。

3、三者使用场景

  • Navigator.sendBeacon:简单、适合在页面卸载时发送少量数据,不处理响应。
  • XHR:功能全面、适合复杂的 AJAX 请求,但使用较复杂。
  • Fetch:现代化接口,简洁灵活,适合处理复杂请求和响应。

五、总结

  1. Navigator.sendBeacon 是一个专为可靠性设计的 API,特别适用于在页面卸载时发送少量数据。
  2. 它具有简单、非阻塞、可靠等优点,特别适合日志记录和用户行为分析等场景。
  3. 发出的是异步请求,并且是 POST 请求。
  4. 只能判断出是否放入浏览器任务队列,不能判断是否发送成功。
  5. 无需处理返回值。
  6. 需要注意浏览器兼容问题。

引用


月恒
40 声望4 粉丝

前端