前端监控系列——Navigator.sendBeacon上报数据🚀🚀🚀

一、前言

上一篇文章我们介绍了关于前端监控的相关内容,包括前端监控的分类,埋点上报的方式,以及采用图片(GIF)做埋点有哪些好处,想了解的小伙伴可以先看这里! 那么这篇文章的话,我们来认识下前端监控中埋点数据上报的另外一种方式 Navigator.sendBeacon !

二、基本介绍

Navigator.sendBeacon 是目前通用的埋点上报方案,可用于通过 HTTP POST 将少量数据 异步 传输到 Web 服务器。它主要用于将统计数据发送到 Web 服务器,同时避免了用传统技术(如:XMLHttpRequest)发送分析数据的一些问题。

基本语法如下:Navigator.sendBeacon方法接受两个参数,第一个参数是目标服务器的 URL,第二个参数是所要发送的数据(可选),可以是任意类型(字符串、表单对象、二进制对象等)

js 复制代码
navigator.sendBeacon(url);
navigator.sendBeacon(url, data);

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

相较于img标签,使用 navigator.sendBeacon 会更规范,数据传输上可传输资源类型会更多。sendBeacon 是异步的,不会影响当前页到下一个页面的跳转速度,且不受同域限制。这个方法还是异步发出请求,但是请求与当前页面脱离关联,作为浏览器的任务,因此可以保证会把数据发出去,不拖延卸载流程。

三、痛点分析

这个方法主要用于满足统计和诊断代码的需要,这些代码通常尝试在卸载(unload)文档之前向 web 服务器发送数据。过早的发送数据可能导致错过收集数据的机会。然而,对于开发者来说保证在文档卸载期间发送数据一直是一个困难,因为用户代理通常会忽略在 unload 事件处理器中产生的异步 XMLHttpRequest

为了解决这个问题, 统计和诊断代码通常要在 unload 或者 beforeunload 事件处理器中发起一个同步 XMLHttpRequest 来发送数据。同步的 XMLHttpRequest 迫使用户代理延迟卸载文档,并使得下一个导航出现的更晚,下一个页面对于这种较差的载入表现无能为力。

过去,为了解决这个问题,统计和诊断代码通常要在

  • 发起一个同步 XMLHttpRequest 来发送数据
  • 创建一个 <img> 元素并设置 src,大部分用户代理会延迟卸载(unload)文档以加载图像
  • 创建一个几秒的 no-op 循环

下面的例子展示了一个理论上的统计代码------在卸载事件处理器中尝试通过一个同步的 XMLHttpRequest 向服务器发送数据,导致了页面卸载被延迟。

js 复制代码
window.addEventListener('unload', logData, false);
 
function logData() {
    var client = new XMLHttpRequest();
    client.open("POST", "/log", false); // 第三个参数表明是同步的 xhr
    client.setRequestHeader("Content-Type", "text/plain;charset=UTF-8");
    client.send(analyticsData);
}

这就是 sendBeacon() 方法存在的意义。使用 sendBeacon() 方法会使用户代理在有机会时异步地向服务器发送数据,同时不会延迟页面的卸载或影响下一导航的载入性能,这意味着:

  • 数据发送是可靠的
  • 数据异步传输
  • 不影响下一导航的载入

四、发送数据的时机

网站通常希望在用户完成页面浏览后向服务器发送分析或诊断数据,最可靠的方法是在 visibilitychange 事件发生时发送数据:

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

我们应该避免使用 unload 和 beforeunload 事件,过去,许多网站使用 unload 事件以在会话结束时发送统计数据。然而这是不可靠的,在许多情况下(尤其是移动设备)浏览器不会产生 unloadbeforeunloadpagehide 事件。下面列出了一种不触发上述事件的情况:

  1. 用户加载了网页并与其交互
  2. 完成浏览后,用户切换到了其他应用程序,而不是关闭选项卡
  3. 随后,用户通过手机的应用管理器关闭了浏览器应用

此外,unload 事件与现代浏览器实现的往返缓存不兼容

五、常见的埋点行为

1. 点击触发埋点

scss 复制代码
function clickButton(url, data) {
    navigator.sendBeacon(url, data)
}

2. 页面停留上报

路由文件中,初始化一个startTime,当页面离开时通过路由守卫计算停留时间

ini 复制代码
let url = ''// 上报地址
let startTime = Date.now()
let currentTime = ''
router.beforeEach((to, from, next) => { 
     if (to) {
         currentTime = Date.now()
         stayTime = parseInt(currentTime - startTime)
         navigator.sendBeacon(url, {time: stayTime})
         startTime = Date.now()
     }
 })

3. 错误监听埋点

(1)Vue 错误捕获

lua 复制代码
app.config.errorHandler = (err) => { 
    navigator.sendBeacon(url, {error: error.message, text: 'vue运行异常' })
}

(2)JS异常与静态资源加载异常,error 可以监听所有同步、异步的运行时错误,但无法监听语法、接口、资源加载错误

vbnet 复制代码
window.addEventListener('error', (error) => { 
    if (error.message) { 
        navigator.sendBeacon(url, {error: error.message, text: 'js执行异常' })
    } else { 
        navigator.sendBeacon(url, {error: error.filename, text: '资源加载异常' })
    } 
}, true)

(3)unhandledrejection 可以监听到 Promise 中抛出的,未被 .catch 捕获的错误

javascript 复制代码
window.addEventListener('unhandledrejection')

(4)请求错误捕获

javascript 复制代码
axios.interceptors.response.use(
  (response) => {
    if (response.code == 200) {
      return Promise.resolve(response);
    } else {
      return Promise.reject(response);
    }
  },
  (error) => {
    // 返回错误逻辑
    navigator.sendBeacon(url, {error: error, text: '请求错误异常' })
  }
);

3. 内容可见埋点

javascript 复制代码
// 可见性发生变化后的回调 
function callback(data) { 
    navigator.sendBeacon(url, { target: data[0].target, text: '内容可见' }) 
} 
// 交叉观察器配置项 
let options = {}; 
// 生成交叉观察器 
const observer = new IntersectionObserver(callback); 
// 获取目标节点 
let target = document.getElementById("target"); 
// 监听目标元素 
observer.observe(target);
相关推荐
编程零零七3 小时前
Python数据分析工具(三):pymssql的用法
开发语言·前端·数据库·python·oracle·数据分析·pymssql
北岛寒沫4 小时前
JavaScript(JS)学习笔记 1(简单介绍 注释和输入输出语句 变量 数据类型 运算符 流程控制 数组)
javascript·笔记·学习
everyStudy4 小时前
JavaScript如何判断输入的是空格
开发语言·javascript·ecmascript
(⊙o⊙)~哦5 小时前
JavaScript substring() 方法
前端
无心使然云中漫步5 小时前
GIS OGC之WMTS地图服务,通过Capabilities XML描述文档,获取matrixIds,origin,计算resolutions
前端·javascript
Bug缔造者5 小时前
Element-ui el-table 全局表格排序
前端·javascript·vue.js
xnian_6 小时前
解决ruoyi-vue-pro-master框架引入报错,启动报错问题
前端·javascript·vue.js
麒麟而非淇淋7 小时前
AJAX 入门 day1
前端·javascript·ajax
2401_858120537 小时前
深入理解MATLAB中的事件处理机制
前端·javascript·matlab
阿树梢7 小时前
【Vue】VueRouter路由
前端·javascript·vue.js