需求:保险购买页面新需求: 为了避免纠纷,需要记录用户操作。
使用rrweb插件记录用户操作的events,并转为txt文档上传阿里云指定文件夹。
目录
一、rrweb 简单介绍
官方介绍:rrweb – record and replay the web,利用现代浏览器所提供的强大 API 录制并回放任意 web 界面中的用户操作。
rrweb是前端js,可以将⻚⾯中的 DOM 以及⽤户操作保存为可序列化的数据,以实现远程回放的一款实用插件。常用于记录用户操作行为,起到监控、回溯、用户行为分析的作用。
项目官网 https://github.com/rrweb-io/rrweb
二、rrweb引入
- 直接通过script引入
<link
rel="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>
- npm安装
npm install --save rrweb
三、rrweb记录行为
// 引入record
<script src="https://cdn.jsdelivr.net/npm/rrweb@latest/dist/record/rrweb-record.min.js"></script>
let events = [];
// 页面刷新开始录制
$(window).ready(function () {
startRecord()
})
// 开始录制
function startRecord() {
let self = this;
// 这里是连接两个页面存在本地的,如果只有一个页面可以忽略这里的判断
if(!window.sessionStorage.getItem('events') || window.sessionStorage.getItem('events')=='') {
events = []
} else {
events = JSON.parse(window.sessionStorage.getItem('events'));
}
window.sessionStorage.removeItem('events');
// 开始录制
rrweb.record({
emit(event) {
events.push(event);
},
sampling: {
// 定义不录制的鼠标交互事件类型,可以细粒度的开启或关闭对应交互录制
mouseInteraction: false,
mousemove: true,
scroll: 150, // 每 150ms 最多触发一次
// 设置输入事件的录制时机
input: 'last' // 连续输入时,只录制最终值
},
});
}
// 停止录制(实际上没用到 ,因为提交订单之后页面跳转了)
let stopFn = rrweb.record({
emit(event) {
if (events.length > 100) {
// 当事件数量大于 100 时停止录制
stopFn();
}
},
});
四、保存录制内容,转为txt文档并上传阿里云
// 保存功能(在提交订单的时候触发)
function saveMyrecord(callback) {
if(!events || events.length == 0){return;}
const body = JSON.stringify(events);
events = [];
var url = '';
var credit = {!! json_encode($sts_info->Credentials) !!};
webUploadTxt(body,credit,function(res) {
// 获取到阿里云txt储存地址(链接)
url = res;
callback(url)
});
}
// 在调用的时候,异步使用url ,上传至后台储存订单信息的接口。
/*
* 上传txt
* */
function webUploadTxt(_this, cred,successCallback) {
let files = _this;
webUpTxtToAli(files, cred,function (data) {
if (successCallback && (typeof successCallback) === 'function') {
successCallback(data);
}
});
}
/*
* 上传TXT到阿里云
* */
function webUpTxtToAli(file, cred,callbackFuc) {
let bucket = $('meta[name="bucket_id"]').attr('content'),
date = new Date(),
_token = $('meta[name="csrf-token"]').attr('content'),
client = void 0;
// 生成随机链接
let storeAs = '储存地址/' + date.format('yyyy-MM-dd_hh.mm.ss') + '-' + Math.round(Math.random()*1000000) + '-' + hex_md5(_token) + '.txt' ;
if (localStorage.Credentials && new Date(JSON.parse(localStorage.Credentials).Expiration).getTime() > new Date().getTime()) { // Credentials.Expiration 过期时间
let Credentials = JSON.parse(localStorage.Credentials);
client = new OSS({
accessKeyId: Credentials.AccessKeyId,
accessKeySecret: Credentials.AccessKeySecret,
stsToken: Credentials.SecurityToken,
region: 'oss-cn-hangzhou',
bucket: bucket
});
} else {
localStorage.Credentials = JSON.stringify(cred);
client = new OSS({
accessKeyId: cred.AccessKeyId,
accessKeySecret: cred.AccessKeySecret,
stsToken: cred.SecurityToken,
region: 'oss-cn-hangzhou',
bucket: bucket
});
}
var fileArr = [];
fileArr.push(file);
// 转为blob对象储存
var result = new Blob(fileArr, {type: 'text/plain'});
client
.put(storeAs, result)
.then(function (res) {
if (callbackFuc && (typeof callbackFuc) === 'function') {
callbackFuc(res.url)
}
})
.catch(function (err) {
console.log(err);
});
}
// 这样我们就可以根据订单号获取用户操作记录的url地址。
五、rrweb回放
- 引入rrweb回放插件
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/rrweb-player@latest/dist/style.css"/>
<script src="https://cdn.jsdelivr.net/npm/rrweb@latest/dist/rrweb.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/rrweb-player@latest/dist/index.js"></script>
- 获取events
var events = [];
let url = {!! json_encode($data_path) !!}; // 获取后台返回的储存的url地址。
// 将地址转为内容,地址是 http://blablabla.txt
function urlToBlob() {
let xhr = new XMLHttpRequest();
xhr.open("get", url, true);
xhr.responseType = "blob";
xhr.onload = function () {
if (this.status == 200) {
console.log(this.response);
const reader = new FileReader();
reader.onload = function () {
events = JSON.parse(reader.result);
// 回放
new rrwebPlayer({
target: document.body, // 可以自定义 DOM 元素
data: {
events,
}
});
};
reader.readAsText(this.response);
}
};
xhr.send();
}
urlToBlob();
六、踩坑的地方
-
使用定时器?
在接到新需求的时候,查阅了很多博客,里面关于rrweb记录的代码很简洁,很多提到了使用定时器进行储存。例如:
这里作者尝试之后,踩雷。发现这样每隔多少秒存一次的方法,会造成大量数据冗余。因为rrweb记录的时候,会首先记录页面内容,而不是操作。页面的dom元素很多,很复杂的情况下,定时记录,会产生大量数据。
解决方法是:一个页面一次记录就可以,页面跳转的时候就会结束录制,保存的数据会小很多。 -
跳转多个页面?
需求里面页面跳转了三个页面,记录的时候也是需要记录下来多个页面的操作记录。例如(第一个页面选择保险方案,跳转到填写投保人被保险人信息页面提交订单。)
解决方法:
在跳转之前可以本地储存events数据,另一个页面记录之前先将events赋值。但是这里还是有个bug,,如果是跳转到提交订单页面的时候,需要返回上一个页面,这样记录的话,由于最后一个页面操作数据过多,本地储存不了,会报错。(也可以跳转回前一个页面的时候重新开始记录。) -
储存方式?
储存方式,刚开始想的是直接将数据存在后台数据库,尝试了几次,发现数据量过大,数据字段过长,因此放弃。
解决方法:
查阅其他码哥做法之后,采用先将这些数据转为txt文档之后储存在阿里云。获取的时候直接根据阿里云返回的txt地址,获取到文档内容,进而进行播放。 -
回放报错?
当events数据只有两条的时候会报错,数据不能低于两条。
当浏览器地址是https开头的时候会跨域报错,改成http就行。(因为服务器没有配置SSL证书,只能通过http请求,这里看服务器配置的是哪个。)