它居然也能实现在页面关闭埋点事件中发送请求?

325 阅读3分钟

一、概述

💡 本文将不再讲述如何选择监听页面卸载关闭的事件,如document.visibilitychange(个人推荐)、beforeunload等。请自行查阅使用哪一种以及用途。

  • 我们在项目开发中也许会想要实现记录用户停留该页面的时间的埋点
  • 然而实现该功能需要在用户离开页面(关闭浏览器、手机切后台等)的时候向服务器发送一个请求 使用传统的请求方式会导致浏览器关闭后请求发送中断
  • 因此为了实现以上需求,我们有两种方法可以选择,一个是navigator.sendBeacon,另外一个则是鲜为人知的fetch结合keepalive属性
  • 或许很多人会疑惑,fetch也能保证请求不会中断取消吗?当然可以,下面会告诉大家它的使用方式。

二、Navigator.sendBeacon()

首先先根据MDN文档简单介绍一下这个方法:

The navigator.sendBeacon() method asynchronously sends an HTTP POST request containing a small amount of data to a web server.

navigator.sendBeacon()方法异步地向web服务器发送包含少量数据的HTTP POST请求。

It's intended to be used for sending analytics data to a web server, and avoids some of the problems with legacy techniques for sending analytics, such as the use of XMLHttpRequest.

它旨在用于将分析数据发送到web服务器,并避免了一些传统技术发送分析的问题,例如使用XMLHttpRequest。

With the sendBeacon() method, the data is transmitted asynchronously when the user agent has an opportunity to do so, without delaying unload or the next navigation. This means:

  • The data is sent reliably
  • It's sent asynchronously
  • It doesn't impact the loading of the next page

The data is sent as an HTTP POST request

使用sendBeacon()方法,当用户代理有机会异步传输数据时,就会异步传输数据,而不会延迟卸载或下一次导航。这意味着:

  • 数据发送可靠
  • 异步发送
  • 不影响下一页的加载

数据以HTTP POST请求发送

Web sites often want to send analytics or diagnostics to the server when the user has finished with the page. The most reliable way to do this is to send the data on the visibilitychange event:

Web站点通常希望在用户使用完页面后向服务器发送分析或诊断。最可靠的方法是发送visbilitychange事件的数据:

document.addEventListener("visibilitychange", function logData() {
  if (document.visibilityState === "hidden") {
    navigator.sendBeacon("/log", analyticsData);
  }
});

developer.mozilla.org/en-US/docs/… 具体看MDN文档

简单来说,使用该方法即便在浏览器关闭卸载之后,它依旧能把通过该方法发送的请求数据发送到服务器上。

不过该方法的缺点也显而易见:

  1. 只能发送POST请求
  2. 无法配置请求头header
  3. 传输的数据量少,并且传输的数据类型只能[ArrayBuffer](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/ArrayBuffer)BlobDOMStringFormData

三、Fetch也能保证请求可靠?

这就不得不提在查看navigator.sendBeacon()文档的时候发现的一段话 image.png 意思是:对于需要使用POST以外的方法发送请求的用例,或者需要更改任何请求属性的用例,或者需要访问服务器响应的用例,可以使用fetch()方法,并将keepalive设置为true。 接下来我们查看MDN文档可以看到

developer.mozilla.org/en-US/docs/…

image.png

意思是:keepalive选项可用于允许请求比页面活得更久。带有keepalive标志的FetchNavigator.sendBeacon() API的替代品。 因此我们可以用以下方式替代Navigator.sendBeacon() API

window.fetch('xxx',{
    headers:{},
    body:{},
    keepalive: true
})

用该方式的优点:

  1. 可以在header上携带Authorization或者其他请求头
  2. 可以使用别的请求方式发送数据
  3. 传输的数据不用被限制在[ArrayBuffer](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/ArrayBuffer)BlobDOMStringFormData这几种。

缺点: 火狐浏览器的兼容性问题等 image.png