基于rrweb框架对web 页面录制与回放
基于rrweb框架对web 页面录制与回放
前言
最近来了个需求需要对web 页面上的操作行为做流程跟踪,并提供具体的数据,或者视频参照,作为合规的证据代码用户的操作轨迹,也避免一些纠纷。
对于web 页面的轨迹追踪,还需要知道操作行为。一想到这个第一想到的就是在线直播学习课程中,找个屏幕录播软件,讲解员打开该软件,开始在电脑上的一切行为都被录制成视频。然后就可以直接把视频分享给所有的人。而你再讲解过程中的一些列细节都能够播放出来。所以当初就想让原生APP开发一个这样类似的东西。再webview中进行播放。这样功能也就ok了。但是还是需要支持移动端web 网页的轨迹追踪。
解决问题方式
思路一:Canvas
利用Canvas截图,使用 html2canvas 库,不停的画页面然后不停的截图,再讲图片播放出来。后来调研了一下~ 发现这个可操作性几乎未零。太复杂了,数据量右大,而我们的页面又复杂,canvas 画半天耗内存,有时候会卡主。直接pass了
思路二:记录页面DOM变化
主要原理是:MutationObserver接口提供了监视对DOM树所做更改的能力。我们可以利用这个接口,保存每次变化的DOM数据,然后把这些数据转换成可视化的数据结构,然后给一个个保存起来。然后我们使用特定的方式对一个个保存起来的DOM数据进行还原并重新渲染出来。DOM节点的变化也就意味了页面轨迹发送了变化。这样就可以把这些轨迹记录下来。我们只需要再把这个还原出来的DOM播放的过程中进行录制,这样就可以保持下来这些轨迹视频。
进行实践
后续调研,以及其他同事的帮助,我们找到了LogRocket ,专业的web app用户行为记录工具,官网描述:
- LogRocket记录用户在你的web上做的一切事情,以帮助你重现bug并更快的解决他们
- 在你的web app中发现问题不应该如此艰难
- 用LogRocket,重现问题就像他们发生在你自己的浏览器中一样
按照其描述,以及我们的进一步了解,发现LogRocket 里面的一些东西确实可以帮助我们解决问题。但是主要问题是还是因为LogRocket 这些数据,我们无法获取到自己的库里面。只能是第三方的库。并不满足我们的需求,还是就是要用它,需要花钱。
大家想深入的了解,可以查看官网 LogRocket 官网
后来我们又了解到一个开源的 rrweb 框架。rrweb主要由3部分组成:
- rrweb-snapshot,包括快照和重建功能。快照用于将DOM及其状态转换为具有唯一标识符的可序列化数据结构; 重建功能是将快照重建为相应的DOM。
- rrweb,包括两个功能:记录和重播。记录功能用于记录DOM中的所有动作变化; 重放是根据相应的时间戳逐个重放记录下的动作变化。
- rweb-player是 rrweb的一个玩家用户界面,可以随时提供基于GUI的功能,如暂停,快进,拖放等功能。
使用这些我们可用于web界面录制以及web界面重放这两个主要功能,rrweb-snapshot 返回的数据结构是json格式的,方便我们前后台数据对接,也规范了这款业务逻辑操作。
rrweb 实践
引入库
(1) 直接通过script引入,推荐通过 jsdelivr 的 CDN 安装:
<linkrel="stylesheet"href="https://cdn.jsdelivr.net/npm/rrweb@latest/dist/rrweb.min.css"
/>
<script src="https://cdn.jsdelivr.net/npm/rrweb@latest/dist/rrweb.min.js"></script>
我们在被录制的应用中只需要引入录制部分代码即可,无需全量引入。
<script src="https://cdn.jsdelivr.net/npm/rrweb@latest/dist/record/rrweb-record.min.js"></script>
(2) 通过 npm 引入rrweb 同时提供 commonJS 和 ES modules 两种格式的打包文件,易于和常见的打包工具配合使用。
npm install --save rrweb
兼容性
由于使用 MutationObserver API,rrweb 不支持 IE11 以下的浏览器。可以从mutationobserver兼容性列表中找到兼容的浏览器列表。
录制开始
如果通过 script 的方式仅引入录制部分,那么可以访问到全局变量 rrwebRecord,它和全量引入时的 rrweb.record 使用方式完全一致,具体看以下示例代码。
// 通过 <script> 的方式,全量引入、npm 引入的
start() {let self = thisthis.operation = rrweb.record({emit(event) {self.events.push(event);},});
}
// 通过 <script> 的方式,仅仅引入录制部分代码
start() {let self = thisthis.operation = rrwebRecord({emit(event) {self.events.push(event);},recordCanvas: true //支持录制canvas//其他参数});
}
rrweb 在录制时会不断将各类 event 传递给配置的 emit 方法,你可以使用任何方式存储这些 event 以便之后回放。
当前rrweb 只支持录制静态的canvas,无法录制动态js生成的canvas.
录制结束
录制结束,rrwebRecord再次执行一遍,即可停止录制。
stop() { this.operation && this.operation()
}
录制数据压缩
引入pako 来对录制的数据进行 gzip压缩,
npm install pako --save
zip(str) {let binaryString = pako.gzip(encodeURIComponent(str), { to: 'string' })return btoa(binaryString);
}
因为录制的是web页面,需要对数据进行encodeURIComponent 一遍,不然解压之后的数据会变成乱码
录制数据解压
unzip(b64Data) { var strData = atob(b64Data);var charData = strData.split('').map(function(x){return x.charCodeAt(0);});var binData = new Uint8Array(charData);var data = pako.inflate(binData);// strData = String.fromCharCode.apply(null, new Uint16Array(data));let array = new Uint16Array(data)var res = '';var chunk = 8 * 1024;var i;for (i = 0; i < array.length / chunk; i++) {res += String.fromCharCode.apply(null, array.slice(i * chunk, (i + 1) * chunk)); }res += String.fromCharCode.apply(null, array.slice(i * chunk));strData = res return decodeURIComponent(strData);
}
Uint16Array 对字符的长度有限制,所以采用分段解压的方式,这样就不会出现内存溢出的问题。
录制数据保存
save(events) {let self = thisif (self.events.length === 0 || events&&events.length === 0) {return Promise.resolve();}const data = JSON.stringify(self.events)let logsParams = { "message": data, "setMessageTime": (new Date().getTime() + '')}const body = JSON.stringify({"__topic__": "topic","__source__": "source","__logs__": [logsParams]});let url = 'xxx保存地址urlxxxxx'return new Promise((resolve, reject) => {fetch(url, {method: 'POST',headers: {'x-log-apiversion': '0.6.0','x-log-bodyrawsize': sizeof(body),'Content-Type': 'application/json',},body,}).catch(error => {reject(error)}).then(response => {resolve(response)})})
}
一个更接近实际真实使用场景的示例如下:
// 每 10 秒调用一次 save 方法,避免请求过多
setInterval(save, 10 * 1000);
// 每调用一次,清空数据
this.events = []
当前我们使用的阿里云的日志接口,也可以改成其他的类似的请求接口。类似官网差不多的。当然我们也可以根据各自的需求,改善自己提交数据的策略。
录制数据播放
(1) 如果 rrweb 是全局引入的情况下,回放时需要引入对应的 CSS 文件:
<linkrel="stylesheet"href="https://cdn.jsdelivr.net/npm/rrweb@latest/dist/rrweb.min.css"
/>
再通过以下 JS 代码初始化 replayer:
const events = YOUR_EVENTS;
const replayer = new rrweb.Replayer(events);
replayer.play();
在实际的应用场景,我们需要异步请求数据,在对数据进行解压,然后再调用JS 。
fetch(url).catch(error => {reject(error)
}).then(res => {//const eventsDate = JSON.stringify(res.data)const events = unzip(eventsDate)const replayer = new rrweb.Replayer(events);replayer.play();
})
(2) 使用 rrweb-player
rrweb-player 同样可以使用 CDN 方式安装:
<linkrel="stylesheet"href="https://cdn.jsdelivr.net/npm/rrweb-player@latest/dist/style.css"
/>
<script src="https://cdn.jsdelivr.net/npm/rrweb-player@latest/dist/index.js"></script>
或者通过 npm 安装:
npm install --save rrweb-player
使用方式:
new rrwebPlayer({target: document.body, // 可以自定义 DOM 元素data: {events,},UNSAFE_replayCanvas: true //支持回放 canvas
});
具体其他的api,或者其他的使用方式,大家可以查看官网
参考网址:
rrweb:打开 web 页面录制与回放的黑盒子
rrweb 官网
rrweb-snapshot 快照
rrweb-player 播放
基于rrweb框架对web 页面录制与回放相关推荐
- 实战Acegi:使用Acegi作为基于Spring框架的WEB应用的安全框架
对于任何一个完整的应用系统,完善的认证和授权机制是必不可少的.在基于SpringFramework的WEB应用中, 我们可以使用Acegi作为安全架构的实现.本文将介绍如何在基于Spring构架的We ...
- 神策数据王磊:如何用 JS 实现页面录制与回放
本文根据神策数据资深前端研发工程师王磊<如何用 JS 实现页面录制与回放>的直播整理而成.以下为正文: 一.业务背景 对于研发来说,总是需要处理一些线上问题.To B 和 To C 企业在 ...
- Ubuntu下利用ipmitool工具解决IPMI(基于openbmc)的web页面崩溃或出现session expired的问题
1.问题出现 如上图,笔者在一年多前买到了一台DDN公司的存储服务器控制器,配置十分的豪华(3647CPU,支持第一代与第二代可拓展志强的正式版,qs与es,1U的空间,六通道内存,支持dcpmm,两 ...
- YMP框架学习笔记(二)------基于YMP框架搭建WEB应用程序
2019独角兽企业重金招聘Python工程师标准>>> 大神的YMP框架:https://github.com/suninformation/ymateplatform.git 1. ...
- 基于Vue框架开发的页面加载二维地图以及交互
一.在Vue项目中引入二维地图 1.切换到公司的仓库下载地图插件 npm config set registry http://nexus.toops.club/repository/npm-zui/ ...
- 基于Vue框架开发的页面加载三维维地图以及交互
一.在Vue项目中引入三维地图 1.安装对应的包 //安装mars3d主库 npm install mars3d --save //安装mars3d插件(按需安装) npm install mars3 ...
- 基于SSM框架的杰森摄影工作室选片系统的设计和开发论文
基于SSM框架的杰森摄影工作室选片系统的设计和开发 摘 要 面对巨大的市场和激烈的竞争,摄影/照相馆行业商家必须紧跟行业发展的步伐,导入新的经营理念和推广方式,才不至于在激烈的市场竞争中被淘汰出局.信 ...
- 实现基于Spring框架应用的权限控制系统(转)
为什么80%的码农都做不了架构师?>>> 前注:当我摸到了通过filter拦截权限,通过AOP拦截方法,通过权限控制菜单的时候,猛然发现这一切的一切已经是别人已经发明好的轮子. ...
- PHP使用声网的页面录制、合流录制、单流录制
为了写着三个录制,发了N多个工单,坑有点大 直接上正文 公共部分 页面录制 合流录制 单流录制 结束录制 结语 直接上正文 公共部分 /*** 获取声网ResourceId* @param $stud ...
- 基于python的界面自动化测试-基于Selenium+Python的web自动化测试框架
一.什么是Selenium? Selenium是一个基于浏览器的自动化测试工具,它提供了一种跨平台.跨浏览器的端到端的web自动化解决方案.Selenium主要包括三部分:Selenium IDE.S ...
最新文章
- DLL: 一种直接法的激光雷达定位方案
- centos7 php配置,CentOS7 下nginx与PHP的安装与配置
- http协议的Request Payload 和 Form Data 的区别
- 中国SaaS死或生之二:ERP两大邪术,尽出歪门邪路
- 各大视觉技术竞赛冠军及 TOP 方案集锦(持续更新)
- linux多线程计算pi,使用蒙特卡洛方法多线程计算pi值
- Spark action算子案例
- 可爱的PNG免扣新年装饰素材,让你海报增加节日气氛
- java怎么系统输入数字_java怎么输入数字,这些经验不可多得
- Win10+caffe+CUDA9.1+vs2013+Matlab2018b+GPU环境,跑通faster_rcnn-master
- Markdown中显示代码段的语法特殊字符`如何输入?
- SAP 客户端不能访问解决方案
- DP/eDP协议学习--视频传输格式
- 雷课堂(THUnderClass)——清华大学2020C++大作业个人项目记录与总结
- 国美易卡网络大数据,国美易卡MySQL数据库
- 韭菜简史:快招加盟的致富骗局
- git文件没有绿色红色小图标解决办法
- login 登陆界面
- NMAP手册中文版(附英文解释版)
- 2018第二届中国通信业物联网大会精彩前瞻