当前位置: 首页 > news >正文

前端实现埋点

前端实现埋点

如何去了解用户呢?最直接有效的方式就是了解用户的行为,了解用户在网站中做了什么,呆了多久。而如何去实现这一操作,这就涉及到我们前端的埋点了。

埋点方式

什么是埋点?

所谓'埋点'是数据采集领域(尤其是用户行为数据采集领域)的术语,指的是针对特定用户行为或事件进行捕获、处理和发送的相关技术及其实施过程。比如用户某个icon点击次数、观看某个视频的时长等等。从数据产品经理视角,聊聊埋点的意义 | 人人都是产品经理 (woshipm.com)

基于此我们可以知道埋点是实际上是对特定事件或者行为的数据监控和上报,常见的埋点上报方式有ajax,img,navigator.sendBeacon下面介绍下这三种埋点上报方式

介绍

因为埋点实际上是对关键节点的数据进行上报,是和服务端交互的一个过程,所以我们可以和后端约定一个接口通过ajax去进行数据上报。

  • 代码实现

我们可以封装一个方法,代码如下:

function buryingPointAjax(data) {return new Promise((resolve, reject) => {// 创建ajax请求const xhr = new XMLHttpRequest();// 定义请求接口xhr.open("post", '/buryingPoint', true);// 发送数据xhr.send(data);});
}

使用时,直接调用即可

let info = {}
buryingPointAjax(info) // 这样就成功上报了info的对象
缺点

一般而言,埋点域名并不是当前域名,因此请求会存在跨域风险,且如果ajax配置不正确可能会被浏览器拦截。因此使用ajax这类请求并不是万全之策。

  • 基于img的埋点上报

上面可以看到如果使用ajax的话,会存在跨域的问题。而且数据上报前端主要是负责将数据传递到后端,并不过分强调前后端交互。因此我们可以通过一些支持跨域的标签去实现数据上报功能。

script,link,img就是我们上报的数据的最好对象

先说结论,这里推荐使用img标签去实现。

script及link的缺陷

因为埋点涉及到请求,因此我们需要保证script和link标签的src可以正常请求。如果需要请求script和link,我们需要将标签挂载到页面上。

验证缺陷

不妨验证下,我们在管理台中加入以下代码:

let a = document.createElement('script')
a.src = 'https://lf-headquarters-speed.yhgfb-cn-static.com/obj/rc-client-security/web/stable/1.0.0.28/bdms.js'

创建一个script标签,未挂载中页面上,并不会发起请求

在这里插入图片描述

书接上文,当我们将这个标签挂载中页面上时:

document.body.appendChild(a);

这时发起了请求

在这里插入图片描述

结论

当我们使用script和link进行埋点上报时,需要挂载到页面上,而反复操作dom会造成页面性能受影响,而且载入js/css资源还会阻塞页面渲染,影响用户体验,因此对于需要频繁上报的埋点而言,script和link并不合适。

基于img做埋点上报

通常使用img标签去做埋点上报,img标签加载并不需要挂载到页面上,基于js去new image(),设置其src之后就可以直接请求图片。

验证img优势

控制台去创建一个image标签,如下:

const img= new Image();
img.src= "https://lf3-cdn-tos.bytescm.com/obj/static/xitu_juejin_web/img/MaskGroup.13dfc4f1.png";

可以看到即便未被挂载到页面上依旧发起了请求。

在这里插入图片描述

结论

因此当我们做埋点上报时,使用img是一个不错的选择。

  1. img兼容性好
  2. 无需挂载到页面上,反复操作dom
  3. img的加载不会阻塞html的解析,但img加载后并不渲染,它需要等待Render Tree生成完后才和Render Tree一起渲染出来

注:通常埋点上报会使用gif图,合法的 GIF 只需要 43 个字节

  • 基于Navigator.sendBeacon的埋点上报

Navigator.sendBeacon是目前通用的埋点上报方案,Navigator.sendBeacon方法接受两个参数,第一个参数是目标服务器的 URL,第二个参数是所要发送的数据(可选),可以是任意类型(字符串、表单对象、二进制对象等等)。

介绍

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

作用

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

补充

sendBeacon 如果成功进入浏览器的发送队列后,会返回true;如果受到队列总数、数据大小的限制后,会返回false。返回ture后,只是表示进入了发送队列,浏览器会尽力保证发送成功,但是否成功了,不会再有任何返回值。

例子

以掘金为例:

在这里插入图片描述

这里发了一个post请求,将小量的数据发到服务端,用于统计数据

在这里插入图片描述

优势

相较于img标签,使用navigator.sendBeacon会更规范,数据传输上可传输资源类型会更多。

对于ajax在页面卸载时上报,ajax有可能没上报完,页面就卸载了导致请求中断,因此ajax处理这种情况时必须作为同步操作。

sendBeacon是异步的,不会影响当前页到下一个页面的跳转速度,且不受同域限制。这个方法还是异步发出请求,但是请求与当前页面脱离关联,作为浏览器的任务,因此可以保证会把数据发出去,不拖延卸载流程。
注意

该方法在支付宝中可能会被拦截,如果发现支付宝数据上报异常,可以尝试排查这块。

总结

前端埋点上报常使用ajax,img,navigator.sendBeacon。不推荐使用ajax。如果考虑兼容性的话,img是不二之选。目前最合适的方案是navigator.sendBeacon,不仅是异步的,而且不受同域限制,而且作为浏览器的任务,因此可以保证会把数据发出去,不影响页面卸载。

常见埋点行为

  1. 点击触发埋点

    绑定点击事件,当点击目标元素时,触发埋点上报。

    function clickButton(url, data) {navigator.sendBeacon(url, data)
    }
    
  2. 页面停留时间上报埋点

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

    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. 错误监听埋点

    通过监听函数去接收错误信息。

    • vue错误捕获
      app.config.errorHandler = (err) => { navigator.sendBeacon(url, {error: error.message, text: 'vue运行异常' })
      }
      
    • JS异常与静态资源加载异常
      window.addEventListener('error', (error) => { if (error.message) { navigator.sendBeacon(url, {error: error.message, text: 'js执行异常' })} else { navigator.sendBeacon(url, {error: error.filename, text: '资源加载异常' })} 
      }, true)
      
    • 请求错误捕获
      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: '请求错误异常' })}
      );
      
  4. 内容可见埋点

    通过交叉观察器去监听当前元素是否出现在页面

    // 可见性发生变化后的回调 
    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);
    

后续

开发的时候可以封装这三种上报方法

// sendBeacon 上报
export async function sendBeacon( {url = '', params }: reportParams) {if (navigator?.sendBeacon && url) {const isSuccess = await navigator?.sendBeacon(url, JSON.stringify(params));if (isSuccess) return true;}return false;
}// img 上报
export function sendImg({ img = '', params }: reportParams) {return new Promise<boolean>((resolve, reject) => {const imageData  = objectToQueryString(params)const img_o = new Image();img_o.onload = () => resolve(true);img_o.onerror = () => reject(false);img_o.src = `${img}?${imageData}`;})
}// ajax 上报
export function sendAjax({ req = '', params }: reportParams) {return new Promise<boolean>((resolve, reject) => {if (req) {postAction(req, params).then(() => resolve(true)).catch(() => reject(false));} else {reject(false);}});
}

使用的时候再导出一个真实上报函数,由用户决定使用什么上报组合。

// 基础上报函数
export async function reportEvent(params: reportParams, reportType:string[] = [IMG, BEACON, AJAX]) {let finalType = falsefor (const key in reportType) {if (!finalType) {try {await EVENT_REPORT_FUNCTION_MAP[key](params).then(()=>{finalType = true})} catch (error) {console.error(error)}}}return finalType
}

相关文章:

前端实现埋点

前端实现埋点 如何去了解用户呢&#xff1f;最直接有效的方式就是了解用户的行为&#xff0c;了解用户在网站中做了什么&#xff0c;呆了多久。而如何去实现这一操作&#xff0c;这就涉及到我们前端的埋点了。 埋点方式 什么是埋点&#xff1f; 所谓埋点是数据采集领域&…...

Apache多后缀解析漏洞分析

漏洞介绍 该漏洞与用户的配置有密切的关系,严格来说属于用户配置问题。Apache文件解析漏洞涉及到 Apache 解析文件的特性。在默认情况下,Apache 允许一个文件具有多个以点分割的后缀,在处理文件时会从右向左识别后缀名。(就是右边的后缀名无法识别,则继续识别左边的) 如果…...

基于Loki + Promtail + Grafana 搭建 Nginx 日志监控

文章目录 引言第一部分&#xff1a;Loki 简介与安装1.1 Loki 简介1.2 Loki 安装1.2.1 下载 Loki1.2.2 安装 Loki 1.3 启动 Loki 第二部分&#xff1a;Promtail 简介与安装2.1 Promtail 简介2.2 Promtail 安装2.2.1 下载 Promtail2.2.2 安装 Promtail 2.3 启动 Promtail 第三部分…...

车载通信架构 —— 传统车内通信网络CAN(可靠性为王)

车载通信架构 —— 传统车内通信网络CAN(可靠性为王) 我是穿拖鞋的汉子,魔都中坚持长期主义的汽车电子工程师。 老规矩,分享一段喜欢的文字,避免自己成为高知识低文化的工程师: 屏蔽力是信息过载时代一个人的特殊竞争力,任何消耗你的人和事,多看一眼都是你的不对。非…...

visual Studio MFC 绘制单一颜色三角形、渐变颜色边框三角形、渐变填充三角形、边框渐变的正方形与填充渐变的正方形实例

MFC 绘制三角形 本文使用visual Studio MFC 平台实现绘制单一颜色三角形、渐变颜色边框三角形、渐变填充三角形、边框渐变的正方形与填充渐变的正方形. 关于基础工程的创建请参考Visual Studio 使用MFC 单文档工程绘制单一颜色直线和绘制渐变颜色的直线 文章目录 MFC 绘制三角形…...

嵌入式八股 | 笔试面试 | 校招秋招 | 题目精选

嵌入式八股精华版1.0所有216道题目如下&#xff1a; 欢迎关注微信公众号【赛博二哈】并加入嵌入式求职交流群。提供简历模板、学习路线、岗位整理等 欢迎加入知识星球【嵌入式求职星球】获取完整嵌入式八股。 提供简历修改、项目推荐、求职规划答疑。另有各城市、公…...

力扣:180. 连续出现的数字(Python3)

题目&#xff1a; 表&#xff1a;Logs ---------------------- | Column Name | Type | ---------------------- | id | int | | num | varchar | ---------------------- 在 SQL 中&#xff0c;id 是该表的主键。 id 是一个自增列。 找出所有至少连续…...

【Python篇】详细讲解正则表达式

文章目录 &#x1f339;什么是正则表达式&#x1f354;语法字符类别重复次数组合模式 ✨例子 &#x1f339;什么是正则表达式 正则表达式&#xff08;Regular Expression&#xff09;&#xff0c;简称为正则或正则表达式&#xff0c;是一种用于匹配、查找和操作文本字符串的工…...

Linux系统分区和挂载超过2T的硬盘

报错信息&#xff1a;DOS partition table format cannot be used on drives for volumes larger than 2199023255040 bytes for 512-byte sectors. Use GUID partition table format (GPT). 转载&#xff1a;Ubuntu(Linux)系统安装扩展硬盘并完成格式化及挂载 - 知乎...

Vue19 列表过滤

直接上代码 以下代码使用了两种实现方式&#xff0c;监视属性和计算属性 当能用计算属性实现时&#xff0c;推荐使用计算属性 <!DOCTYPE html> <html><head><meta charset"UTF-8" /><title>列表过滤</title><script type&q…...

【一起来学kubernetes】7、k8s中的ingress详解

引言配置示例负载均衡的实现负载均衡策略实现模式实现方案Nginx类型Ingress实现Treafik类型Ingress实现HAProxy类型ingress实现Istio类型ingress实现APISIX类型ingress实现 更多 引言 Ingress是Kubernetes集群中的一种资源类型&#xff0c;用于实现用域名的方式访问Kubernetes…...

[Java] 阿里一面~说一下ArrayList 与 LinkedList 区别

文章目录 是否保证线程安全底层数据结构插入和删除是否受元素位置的影响是否支持快速随机访问内存空间占用&#xff1a; 是否保证线程安全 ArrayList 和 LinkedList 都是不同步的&#xff0c;也就是不保证线程安全&#xff1b; 底层数据结构 ● ArrayList 底层使用的是 Obje…...

凸包问题的GRAHAM-SCAN解法 open3d c++ 代码

使用了Open3D库进行点云处理和可视化。下面是代码的大致解释: 引入必要的头文件和命名空间: 定义了三个函数: ComputeTriangleDirArea:计算带符号三角形的面积。Compute2Ddistance:计算两点之间的平面距离。GetConvexHullByGrahamScan:通过Graham Scan方法计算凸包点集。…...

从微软Cosmos DB浅谈一致性模型

最近回顾了微软的Cosmos DB的提供一致性级别&#xff0c;重新整理下一致性模型的相关内容。 0. Cosmos DB Cosmos DB&#xff08;Azure Cosmos DB&#xff09;是由微软推出的一个支持多模型、多 API 的全球分布式数据库服务。它旨在提供高度可扩展性、低延迟、强一致性和全球…...

spring-webmvc练习-日程管理-访问后端展示列表数据

1、util/request.js import axios from "axios";let request axios.create({baseURL: "http://localhost:8080",timeout: 50000 });export default request 2、api/schedule.js import request from "../util/request.js";export let getSchedu…...

【Linux系统编程】操作系统详解(什么是操作系统?为什么会存在操作系统?设计操作系统的目的是什么?)

目录 一、前言 二、 什么是操作系统 &#x1f4a6;操作系统的引入 &#x1f4a6;操作系统的概念理解 &#x1f4a6;操作系统设计的目的与定位 &#x1f4a6;总结 二、操作系统之上之下分别有什么 三、深度理解操作系统的“管理” &#x1f4a6;场景理解 &#x1f4a6;操…...

肖sir __数据库练习__001

建表语句&#xff1a; create table student ( id int(4),age int(8),sex int(4),name varchar(20), class int(4), math int(4)) DEFAULT charsetutf8; INSERT into student VALUES(1,25,1,‘zhansan’,1833,90); INSERT into student VALUES(2,25,1,‘lisi’,1833,67); INSER…...

【数据结构初阶】树,二叉树

树&#xff0c;二叉树 1.树概念及结构1.1树的概念1.2 树的相关概念1.3 树的表示1.4 树在实际中的运用&#xff08;表示文件系统的目录树结构&#xff09; 2.二叉树概念及结构2.1概念2.2现实中的二叉树2.3 特殊的二叉树2.4 二叉树的性质2.5 二叉树的存储结构 1.树概念及结构 1.…...

HTML新手入门笔记整理:HTML常用标签总结表

HTML常用标签 标签 英文全称 语义 div division 区块(块元素) span span 区块(行内元素) p paragraph 段落 ol ordered list 有序列表 ul unordered list 无序列表 li list item 列表项 dl definition list 定义列表 dt definition term 定义术语 d…...

Linux7安装mysql数据库以及navicat远程连接mysql

1.下载地址&#xff1a;MySQL :: Download MySQL Community Server 2.创建mysql目录将压缩包上传到该目录 mkdir /opt/mysql cd /opt/mysql3.解压压缩包 gzip mysql-8.1.0-1.el7.x86_64.rpm-bundle.tar tar -zxvf mysql-8.1.0-1.el7.x86_64.rpm-bundle.tar.gz 4.前置检查 ch…...

抖音增长新引擎:品融电商,一站式全案代运营领跑者

抖音增长新引擎&#xff1a;品融电商&#xff0c;一站式全案代运营领跑者 在抖音这个日活超7亿的流量汪洋中&#xff0c;品牌如何破浪前行&#xff1f;自建团队成本高、效果难控&#xff1b;碎片化运营又难成合力——这正是许多企业面临的增长困局。品融电商以「抖音全案代运营…...

Spring AI与Spring Modulith核心技术解析

Spring AI核心架构解析 Spring AI&#xff08;https://spring.io/projects/spring-ai&#xff09;作为Spring生态中的AI集成框架&#xff0c;其核心设计理念是通过模块化架构降低AI应用的开发复杂度。与Python生态中的LangChain/LlamaIndex等工具类似&#xff0c;但特别为多语…...

现有的 Redis 分布式锁库(如 Redisson)提供了哪些便利?

现有的 Redis 分布式锁库&#xff08;如 Redisson&#xff09;相比于开发者自己基于 Redis 命令&#xff08;如 SETNX, EXPIRE, DEL&#xff09;手动实现分布式锁&#xff0c;提供了巨大的便利性和健壮性。主要体现在以下几个方面&#xff1a; 原子性保证 (Atomicity)&#xff…...

并发编程 - go版

1.并发编程基础概念 进程和线程 A. 进程是程序在操作系统中的一次执行过程&#xff0c;系统进行资源分配和调度的一个独立单位。B. 线程是进程的一个执行实体,是CPU调度和分派的基本单位,它是比进程更小的能独立运行的基本单位。C.一个进程可以创建和撤销多个线程;同一个进程中…...

解读《网络安全法》最新修订,把握网络安全新趋势

《网络安全法》自2017年施行以来&#xff0c;在维护网络空间安全方面发挥了重要作用。但随着网络环境的日益复杂&#xff0c;网络攻击、数据泄露等事件频发&#xff0c;现行法律已难以完全适应新的风险挑战。 2025年3月28日&#xff0c;国家网信办会同相关部门起草了《网络安全…...

MySQL 部分重点知识篇

一、数据库对象 1. 主键 定义 &#xff1a;主键是用于唯一标识表中每一行记录的字段或字段组合。它具有唯一性和非空性特点。 作用 &#xff1a;确保数据的完整性&#xff0c;便于数据的查询和管理。 示例 &#xff1a;在学生信息表中&#xff0c;学号可以作为主键&#xff…...

HybridVLA——让单一LLM同时具备扩散和自回归动作预测能力:训练时既扩散也回归,但推理时则扩散

前言 如上一篇文章《dexcap升级版之DexWild》中的前言部分所说&#xff0c;在叠衣服的过程中&#xff0c;我会带着团队对比各种模型、方法、策略&#xff0c;毕竟针对各个场景始终寻找更优的解决方案&#xff0c;是我个人和我司「七月在线」的职责之一 且个人认为&#xff0c…...

如何配置一个sql server使得其它用户可以通过excel odbc获取数据

要让其他用户通过 Excel 使用 ODBC 连接到 SQL Server 获取数据&#xff0c;你需要完成以下配置步骤&#xff1a; ✅ 一、在 SQL Server 端配置&#xff08;服务器设置&#xff09; 1. 启用 TCP/IP 协议 打开 “SQL Server 配置管理器”。导航到&#xff1a;SQL Server 网络配…...

【无标题】湖北理元理律师事务所:债务优化中的生活保障与法律平衡之道

文/法律实务观察组 在债务重组领域&#xff0c;专业机构的核心价值不仅在于减轻债务数字&#xff0c;更在于帮助债务人在履行义务的同时维持基本生活尊严。湖北理元理律师事务所的服务实践表明&#xff0c;合法债务优化需同步实现三重平衡&#xff1a; 法律刚性&#xff08;债…...

结构化文件管理实战:实现目录自动创建与归类

手动操作容易因疲劳或疏忽导致命名错误、路径混乱等问题&#xff0c;进而引发后续程序异常。使用工具进行标准化操作&#xff0c;能有效降低出错概率。 需要快速整理大量文件的技术用户而言&#xff0c;这款工具提供了一种轻便高效的解决方案。程序体积仅有 156KB&#xff0c;…...