使用sendBeacon进行前端数据上报

目录

前言

上报数据的时机

上报数据的方法

1. 直接发请求上报

2. 动态图片

3. sendBeacon

总结


前言

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

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

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

上述的所有方法都会迫使用户代理延迟卸载文档,并使得下一个导航出现的更晚。下一个页面对于这种较差的载入表现无能为力。

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

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

数据是通过 HTTP POST 请求发送的。

上报数据的时机

  • 页面加载时

此时进行数据上报,只需要在页面 load 时上报即可。

window.addEventListener('load', reportData, false);
  • 页面卸载或页面刷新时

此时进行数据上报,只需要在页面 beforeunload 时上报即可。

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

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

此外,unload 事件与现代浏览器实现的往返缓存(bfcache)不兼容。在部分浏览器(如:Firefox)通过在 bfcache 中排除包含 unload 事件处理器的页面来解决不兼容问题,但这存在性能损失。其他浏览器,例如 Safari 和 Android 上的 Chrome 浏览器则采取用户在同一标签页下导航至其他页面时不触发 unload 事件的方法来解决不兼容问题。

Firefox 也会在 bfcache 中排除包含 beforeunload 事件处理器的页面。

使用 pagehide 作为回退

可使用 pagehide 事件来代替部分浏览器未实现的 visibilitychange 事件。和 beforeunload 与 unload 事件类似,这一事件不会被可靠地触发(特别是在移动设备上),但它与 bfcache 兼容。

window.addEventListener('beforeunload', reportData, false);

如果是这种情况,可以在 visibilitychange 时通过读取 document.visibilityState 或 document.hidden 区分页面 tab 的激活状态,判断是否需要进行上报。

  • SPA 路由切换时
    • 如果是 vue-router 或 react-router@3 及以下版本,则可以在 hooks 里进行上报操作。
    • 如果是 react-router@4 则需要在 Routes 根组件的生命周期内进行上报。
  • 页面多个 tab 切换时

当其选项卡的内容变得可见或被隐藏时,会在 document 上触发 visibilitychange 事件。

当用户导航到新页面、切换标签页、关闭标签页、最小化或关闭浏览器,或者在移动设备上从浏览器切换到不同的应用程序时,该事件就会触发,其 visibilityState 为 hidden。过渡到 hidden 是页面能可靠观察到的最后一个事件,因此开发人员应将其视为用户会话的可能结束(例如,用于发送分析数据)。

 

document.addEventListener("visibilitychange", function() {if(document.visibilityState === 'visible') {reportData();}if(document.visibilityState === 'hidden') {reportData2();}// your code ...
});

上报数据的方法

1. 直接发请求上报

我们可以直接将数据通过 ajax 发送到后端,以 axios 为例。

axios.post(url, data);

但这种方法有一个问题,就是在页面卸载或刷新时进行上报的话,请求可能会在浏览器关闭或重新加载前还未发送至服务端就被浏览器 cancel 掉,导致数据上报失败。

我们可以将 ajax 请求改为同步方法,这样就能保证请求一定能发送到服务端。由于 fetch 及 axios 都不支持同步请求,所以需要通过 XMLHttpRequest 发送同步请求。

const syncReport = (url, { data = {}, headers = {} } = {}) => {const xhr = new XMLHttpRequest();xhr.open('POST', url, false);xhr.withCredentials = true;Object.keys(headers).forEach((key) => {xhr.setRequestHeader(key, headers[key]);});xhr.send(JSON.stringify(data));
};

这里要注意的是,将请求改为同步以后,会阻塞页面关闭或重新加载的过程,这样就会影响用户体验。

2. 动态图片

我们可以通过在 beforeunload 事件处理器中创建一个图片元素并设置它的 src 属性的方法来延迟卸载以保证数据的发送,因为绝大多数浏览器会延迟卸载以保证图片的载入,所以数据可以在卸载事件中发送。

const reportData = (url, data) => {let img = document.createElement('img');const params = [];Object.keys(data).forEach((key) => {params.push(`${key}=${encodeURIComponent(data[key])}`);});img.onload = () => img = null;img.src = `${url}?${params.join('&')}`;
};

此时服务端可以返回一个 1px * 1px 的图片,保证触发 img 的 onload 事件,但如果某些浏览器在实现上无法保证图片的载入,就会导致上报数据的丢失。

3. sendBeacon

为了解决上述问题,便有了 navigator.sendBeacon 方法,使用该方法发送请求,可以保证数据有效送达,且不会阻塞页面的卸载或加载,并且编码比起上述方法更加简单。

用法如下:

navigator.sendBeacon(url, data);

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

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

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

  • DOMString

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

const reportData = (url, data) => {navigator.sendBeacon(url, data);
};
  • Blob
  • 如果用 Blob 发送数据,这时需要我们手动设置 Blob 的 MIME type,一般设置为 application/x-www-form-urlencoded

    javascript

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

 

可以直接创建一个新的 Formdata,此时该请求会自动设置请求头的 Content-Type 为 multipart/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 或 Blobvalue = JSON.stringify(value);}formData.append(key, value);});navigator.sendBeacon(url, formData);
};

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

总结

我们可以使用 sendBeacon 发送数据,这一方法既能保证数据可靠性,也不影响用户体验,如果浏览器不支持该方法,则可以降级使用同步的 ajax 发送数据。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/bicheng/31297.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

微信公众号多域名回调系统V1.5 源码

这是一款基于ThinkPHP6.0开发的微信公众号多域名回调系统。本系统有如下功能&#xff1a; 微信公众号多域名回调功能&#xff1a;微信公众号后台默认只能授权2个网页域名&#xff0c;用本系统突破这个限制&#xff0c;用同一个公众号对接无限多个网站。网站后台支持回调域名白…

王者荣耀图鉴皮肤怎么来的

王者荣耀图鉴皮肤怎么来的 最近一个王者荣耀图鉴开源很火 这个项目里面有很多的图片和音效资源&#xff0c;最简单的方法就是利用爬虫技术爬取这些图片资源。 第一步环境准备 Pyhton3.12macos系统 第二步查看王者荣耀官网 这些图片资源最简单的来源就是王者荣耀官网网站…

【FPGA + Nvidia/算能GPU+AI】自动驾驶多核异构实现 16路车载摄像头实时AI分析解决方案

基于 Xilinx 公司ZYNQ Ultrascale MPSoC系列 FPGA 芯片设计&#xff0c;应用于无人驾驶、慢速特种车及数据采集车、车载仿真测试系统等自动驾驶领域 自动驾驶&#xff1a;16通道车载摄像头PCIE采集卡方案。 16 通道摄像头 最多支持 16 通道 GMSL1/2 摄像头输入 8MP 摄像头 最…

MyBatisplus使用报错--Invalid bound statement

报错如下 org.apache.ibatis.binding.BindingException: Invalid bound statement (not found): com.lotus.mybatis.mapper.UserMapper.selectListat org.apache.ibatis.binding.MapperMethod$SqlCommand.<init>(MapperMethod.java:235)at com.baomidou.mybatisplus.cor…

ModelScope联手OpenDataLab:直接调用7000+开源数据集,赋能AI模型加速研发

在人工智能的演进历程中&#xff0c;数据和模型的整合是推动技术发展的核心动力。随着AI技术的不断进步&#xff0c;整合各类关键资源&#xff0c;构建一个高效、协同的开发环境&#xff0c;已成为加速创新应用发展的关键。 基于这一理念&#xff0c;OpenDataLab浦数与ModelSc…

python基础篇(4):range语句

1 功能介绍 range语句的功能是获得一个数字序列&#xff08;可迭代类型的一种&#xff09; 2 语法 语法1&#xff1a; range(num) 获取一个从0开始&#xff0c;到num结束的数字序列&#xff08;不含num本身&#xff09; 如range(5)取得的数据是&#xff1a;[0, 1, 2, 3, 4…

在华为服务器上编译C++工程的若干错误以及排查方法和解决方法记录

目录 1 报错 2 查找错误原因 2.1 方法一&#xff1a;ldd命令 2.2 方法二&#xff1a;警告信息里面 3 解决错误 3.1 libpng16.so.16 和 libbrotlidec.so.1 问题 3.2 libdevmmap.so 和 libslog.so库问题 3.3 剩余错误 3.3.1 libacllite.so错误解决 3.3.2 libtaclstream…

通过自定义分配器解决 ZGC中的碎片问题

1.问题 ZGC 和其他垃圾收集器通常使用碰撞指针分配&#xff0c;这对于顺序分配很有效&#xff0c;但随着时间的推移会导致碎片化。当产生无法轻松重用的内存间隙时&#xff0c;就会发生碎片化&#xff0c;这需要昂贵的活动对象重新定位。这项研究的目标是通过使用基于空闲列表…

LCP 61. 气温变化趋势

题目 力扣城计划在两地设立「力扣嘉年华」的分会场&#xff0c;气象小组正在分析两地区的气温变化趋势&#xff0c;对于第 i ~ (i1) 天的气温变化趋势&#xff0c;将根据以下规则判断&#xff1a; 若第 i1 天的气温 高于 第 i 天&#xff0c;为 上升 趋势若第 i1 天的气温 等…

Flash页、扇区、块的区别

文章目录 前言玩转Flash的小知识一、页(Page)二、扇区(Sector)三、块(Block)总结存储基础知识 瑞萨芯片简介(片上资源分配)和工具链使用 前言 FLASH 存储器又称闪存,它结合了ROM和RAM的长处,不仅具备电子可擦除可编程(EEPROM)的性能,还不会断电丢失数据同时可以快速…

用java写一个二叉树翻转

class TreeNode {int val;TreeNode left, right;TreeNode(int val) {this.val val;left right null;} }public class BinaryTree {TreeNode root;// 递归翻转二叉树public TreeNode invertTree(TreeNode root) {if (root null) {return null;}// 递归翻转左子树和右子树Tre…

SpringBoot测试实践

测试按照粒度可分为3层&#xff1a; 单元测试&#xff1a;单元测试&#xff08;Unit Testing&#xff09;又称为模块测试 &#xff0c;是针对程序模块&#xff08;软件设计的最小单位&#xff09;来进行正确性检验的测试工作。程序单元是应用的最小可测试部件。在过程化编程中…

【自动驾驶】ROS小车系统、运动底盘的运动学分析和串口通信控制

文章目录 小车组成轮式运动底盘的组成轮式运动底盘的分类轮式机器人的控制方式感知传感器ROS决策主控ROS介绍ROS的坐标系ROS的单位机器人电气连接变压模块运动底盘的电气连接ROS主控与传感器的电气连接ROS主控和STM32控制器两种控制器的功能运动底盘基本组成电池电机控制器与驱…

WPF将dll文件嵌入到exe文件中

WPF将dll文件嵌入到exe文件中 第一步&#xff1a;打开.csproj文件&#xff0c;在Import节点后添加如下代码&#xff1a; <Target Name"AfterResolveReferences"><ItemGroup><EmbeddedResource Include"(ReferenceCopyLocalPaths)" Condit…

AI视频教程下载-用LangChain 开发 OpenAI、 LLAMA 、 Gemini 等AI应用

LangChain MasterClass- OpenAI LLAMA 2 GPT LLM Apps__ Python&#xff08;LangChain MasterClass-Develop 7 OpenAI LLM Apps using Python&#xff09; 探索LangChain、Pinecone、OpenAI、LLAMA 2及Google Gemini Pro LLM在现实世界中的应用。构建AI应用——拥抱脸&#xff…

写一个可以批量修改图片分辨率的工具

说在前面 &#x1f388;在视觉内容至关重要的今天&#xff0c;图片尺寸的调整对于网站加载速度和用户体验有着直接影响。本文介绍的Node.js工具&#xff0c;通过简单的命令行操作&#xff0c;允许用户批量调整图片尺寸&#xff0c;支持单张图片和整个目录的操作&#xff0c;提供…

逆向学习网络篇:数据传输和交换过程

本节课在线学习视频&#xff08;网盘地址&#xff0c;保存后即可免费观看&#xff09;&#xff1a; ​​https://pan.quark.cn/s/3d8ae684d031​​ 网络技术是现代信息社会的基础&#xff0c;它涉及数据传输、交换和存储等多个方面。本文将深入探讨网络中的数据传输和交换过程…

【机器学习】---无监督学习

引言 在机器学习的广阔领域中&#xff0c;无监督学习扮演着至关重要的角色。不同于有监督学习&#xff0c;无监督学习处理的是没有标签的数据集&#xff0c;即我们不知道每个数据点的正确答案或分类。然而&#xff0c;这并不意味着无监督学习无法为我们提供有价值的信息。相反…

DDOS攻击会造成哪些问题

DDOS攻击是我们日常生活中比较常见的一种网络攻击&#xff0c;DDOS攻击的全称为分布式拒绝服务攻击&#xff0c;游戏行业则是DDOS攻击的重灾区&#xff0c;本文主要来给大家讲解一下DDOS攻击会给业务造成哪些问题吧&#xff01; DDOS攻击是攻击者利用大量的恶意请求占用了目标服…

AI音乐:创新引擎还是创意终结者?

✨作者主页&#xff1a; Mr.Zwq✔️个人简介&#xff1a;一个正在努力学技术的Python领域创作者&#xff0c;擅长爬虫&#xff0c;逆向&#xff0c;全栈方向&#xff0c;专注基础和实战分享&#xff0c;欢迎咨询&#xff01; 您的点赞、关注、收藏、评论&#xff0c;是对我最大…