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

阿里云日志服务之WebTracking 小程序端 JavaScript SDK (阿里SDK埋点和原生uni.request请求冲突问题)

目录标题

  • 1、官方文档
  • 2、安装和配置sdk
  • 3、自定义封装埋点事件,进行日志上报

1、官方文档

阿里云日志服务官方文档

2、安装和配置sdk

npm install --save @aliyun-sls/web-track-mini

使用下面方式,既能解决请求冲突问题,又不会丢失日志信息

// webTracker.js
import SlsTracker from '@aliyun-sls/web-track-mini'
import {logFlag
} from '@/utils/logger.js'
import {AppState
} from '@/utils/globalState.js';
export default class webTracker {/**** @param slsConfig 阿里云上传参数* @param publicParam 项目标准公参* @param projectArgs 项目个性化公参*/constructor(slsConfig, publicParam = {}, projectArgs = {}) {// this.tracker = new SlsTracker(slsConfig)// logFlag && console.log('创建SlsTracker对象this.tracker:',this.tracker)// 800ms延迟确保普通请求优先处理// 避免SLS初始化期间拦截有效请求:当SLS初始化未完成时,直接调用uni.request会导致请求丢失setTimeout(() => {this.tracker = new SlsTracker({...slsConfig,// opt:接收完整的uni.request配置对象(含url/method/data等)// 通过call(uni)显式绑定uni-app运行环境,避免this指向错误// 强制所有SLS日志请求通过uni-app原生方法发出,确保上下文绑定和参数透// 严格兼容uni-app环境‌时(如小程序、H5混合开发),必须使用自定义request配置,在‌纯浏览器环境‌或对请求无特殊要求时,可省略该配置// 如果不使用request配置将导致:SDK初始化阶段请求方法未就绪导致的调用失败||跨平台运行时出现的this指向混乱 || 特殊header或参数被SDK默认实现过滤// _originalRequest:指向‌备份的原始请求方法‌(通常是对 uni.request 的引用)// 头函数 (opt) => _originalRequest.call(uni, opt) 会 ‌继承外层作用域的变量‌(即模块作用域中的 _originalRequest),无需额外处理request: (opt) => _originalRequest.call(uni, opt)});AppState.setSLSReady(true); // 更新全局状态this._flushQueue();}, 800);this._queue = []; // 日志暂存队列// 项目标准公参// 保留字段系日志服务自动生成,无需进行埋点 (日志来源、上报时间、主题、分区时间、其它日志字段)this.params = {// log_source: '', // 日志来源// log_time: Math.floor(Date.now() / 1000), // 日志上报时间// log_topic: '', // 日志主题// log_partition_time: 'null', // 分区时间// log_extract_others: '', // 其他日志字段...publicParam}// 项目个性化公参this.args = {...projectArgs}}/*** 更新参数* @param publicParam 项目标准公参* @param projectArgs 项目个性化公参*/updateParam(publicParam = {}, projectArgs = {}) {this.params = {...this.params,...publicParam,}this.args = {...this.args,...projectArgs}}// 改造send方法(关键修改)send(params, args) {const sendParam = this._buildParams(params, args);if (AppState.slsReady) {this.tracker.sendImmediate(sendParam);} else {this._queue.push({type: 'single',data: sendParam});}}// 改造sendBatch方法(关键修改)sendBatch(arr) {const batchParams = arr.map(item => this._buildParams(item));if (AppState.slsReady) {this.tracker.sendBatchLogsImmediate(batchParams);} else {this._queue.push({type: 'batch',data: batchParams});}}// 新增私有方法_buildParams(params, args = {}) {let allParams = {...this.params,...params,args: JSON.stringify({...this.args,...args,...params.args,})};logFlag && console.log(`***当前${allParams.event_name}事件日志上报数据allParams***:`, allParams)return allParams}_flushQueue() {this._queue.forEach(item => {item.type === 'single' ?this.tracker.sendImmediate(item.data) :this.tracker.sendBatchLogsImmediate(item.data);});this._queue = [];}/*** 点击事件*/click(params, args) {this.send(params, args)}/*** 发送统计事件*/// send(params, args) {// 	//项目标准公参,埋点事件相关字段,项目个性化公参,埋点事件相关args字段//    let sendParam =  this._buildParams(params, args);//    logFlag && console.log('发送统计事件sendParam:',sendParam)//    this.tracker.sendImmediate(sendParam)// }/*** 组合发送统计事件*/// sendBatch(arr) {//     let batchParams = arr.map(item => this._buildParams(item));// 	logFlag && console.log('组合发送统计事件batchParams:',batchParams)//     this.tracker.sendBatchLogsImmediate(batchParams)// }}
// globalState.js
// 导出一个全局状态管理对象 AppState
export const AppState = {// SLS(日志服务)就绪状态标志位,默认false表示未就绪slsReady: false,  // 替代旧变量 _slsReady,命名更规范// 设置SLS就绪状态的方法setSLSReady(value) {// 更新当前对象的slsReady状态this.slsReady = value;// 通过uni-app的事件总线触发全局事件// 参数说明:// - 'sls-ready': 事件名称,其他组件可监听此事件// - value: 传递的状态值(true/false)uni.$emit('sls-ready', value); }
};
// request.js
// 在ES6模块(import/export)中,顶层变量(非函数内部声明)默认具有 ‌模块级作用域‌,即同一模块内的所有代码均可访问,且不会污染全局命名空间
// 保留原始请求方法引用,确保即使SDK初始化失败也能回退到原始请求
const _originalRequest = uni.request;
// SLS初始化状态标识
import {AppState
} from '@/utils/globalState.js';// 将以下:接口请求方式
uni.request({}) 
// 替换为
// 动态选择请求方法(核心修改)
// slsReady=false:使用原始方法(绕过SDK)  slsReady=true:切换到SDK增强方法
const requestExecutor = AppState.slsReady ? uni.request : _originalRequest;
//call(uni, {...}) 上下文绑定, 显式绑定uni-app运行环境,确保请求方法中的this指向正确,避免回调函数丢失uni对象。
requestExecutor.call(uni, {})

3、自定义封装埋点事件,进行日志上报

import webTracker from './webTracker.js'const opts = {host: '', // 所在地域的服务入口。project: '', // Project名称。logstore: '' // Logstore名称。
}// 项目标准公参
const publicParam = {}// 项目个性化公参
const projectArgs = {}//new webTracker(阿里云上传参数、项目标准公参、项目个性化公参)
export const tracker = new webTracker(opts, publicParam, projectArgs)/*** 更新参数 (项目标准公参 + 项目个性化公参 )* 针对缓存本地数据,再次放入(防止埋点加载太快,没有获取到缓存数据)*/
export const updateParam = () => {tracker.updateParam({//...项目标准公参}, {//...项目个性化公参})
}/*** 发送统计事件*/
export const send = (data, args) => {updateParam()tracker.send(data, args)
}/*** 组合发送统计事件*/
export const sendBatch = (data) => {updateParam()tracker.sendBatch(data)
}/*** 点击事件*/
export const click = (data, args) => {updateParam()tracker.click(data, args)
}// 以下是事件方法:/*** 小程序启动事件*/
export const triggerLoad = (trackData) => {let data = {}let args = {}send(data, args)
}/*** 小程序退出*/
export const triggerMpend = (trackData) => {let data = {}let args = {}send(data, args)
}/*** 曝光事件*/
export const triggerExposure = (trackData) => {let data = {// ...args: {// ...}}sendBatch(data)
}/*** 批量曝光事件*/
let triggerExposureArr = []
let triggerExposureTimer = null
export function triggerExposureBatch(trackData) {let data = {// ...args: {// ....}}triggerExposureArr.push(data)if (triggerExposureTimer === null) {triggerExposureTimer = setTimeout(() => {sendBatch(triggerExposureArr)clearTimeout(triggerExposureTimer)triggerExposureTimer = nulltriggerExposureArr = []}, 500)}
}export default {tracker,// 发送统计事件send,// 点击事件click,// 组合发送统计事件sendBatch,// 更新参数 (项目标准公参 + 项目个性化公参 )updateParam,// 小程序启动事件triggerLoad,// 小程序退出triggerMpend,// 曝光事件triggerExposure,// 批量曝光事件triggerExposureBatch,
}
http://www.xdnf.cn/news/19518.html

相关文章:

  • 2025全球绿色发展与健康生活方式高峰论坛 推动HLCC国际认证体系全球化实施
  • VGG改进(7):基于Spatial Attention的性能优化
  • 跨平台游戏引擎 Axmol-2.8.0 发布
  • Prettier代码格式化工具测评:支持JS/TS/Vue多语言,兼容ESLint实现团队代码格式统一
  • TKDE-2022《Low-Rank Linear Embedding for Robust Clustering》
  • Element-Plus 入门指南
  • 【3D通用视觉框架】基于Qt5开发的3D视觉框架软件,纯底层,全套源码,开箱即用
  • R语言根据经纬度获得对应样本的省份
  • PCB设计规范
  • redis-----java客户端
  • K8s集群+Rancher Server:部署DolphinScheduler 3.2.2集群
  • 【vue2】vue2.7x的项目中集成tailwind.css真的不要太香
  • GPT-5在医疗领域应用的研究效能初探(上)
  • Elasticsearch赋能3D打印机任务统计分析
  • 【图像处理基石】图像预处理方面有哪些经典的算法?
  • 聚铭网络实力蝉联数说安全“2025年中国网络安全市场100强”
  • 【C++游记】红黑树
  • Lombok 实用注解深度解析!
  • 【项目】多模态RAG—本地部署MinerU实现多类文档解析
  • 懒加载详细讲解
  • 使用修改过的arj源码编译和测试
  • C++ 学习与 CLion 使用:(五)数据类型,包括整型、实型、字符型、转义字符、字符串、布尔型
  • 从DevOps到BizDevOps:哪些DevOps工具能够成为业务创新加速引擎?
  • 响应式编程框架Reactor【8】
  • Notepad++近期版本避雷
  • 中心扩展算法
  • 如何解决pip安装报错ModuleNotFoundError: No module named ‘tox’问题
  • 利用 DrissionPage 精准获取淘宝商品描述:Python 爬虫实战指南
  • C/C++、Python和Java语言的比较
  • 【职业】算法与数据结构专题