准备工作,需要使用到的包有
rrweb(录制)
rrwebPlayer(播放)
pako(压缩)
import * as rrweb from 'rrweb'
let dispose = null
let rrwebEvents = []
console.log('开始录制 ========>>>>>>>>>>>>>>')
clearFile(); // 录制之前清楚本地缓存json文件
dispose = rrweb.record({
emit(event) {
rrwebEvents.push(event);
// 以 rrwebEvents 的长度作为分片持续上传:
if(rrwebEvents.length >= 50) {
uploadFile();
// 分片之后清空队列:
rrwebEvents = [];
}
}
})
console.log('结束录制 ========>>>>>>>>>>>>>>')
if (dispose) {
// 实际场景需要分片传输的话,就不需要这个关闭,当真正业务不需要录制的时候再调用
// 分片逻辑是,序列化的rrwebEvents.length的累加大于某个值 --- 分片逻辑看业务需求吧
// 我们这里上传的时候是 gzip 后的文件上传,不是用的json方式,也需要后端解gzip,这里只负责演示前端,所以压缩逻辑就没写上
// 压缩逻辑是 引入pako, 然后调用,就不体现了哈
dispose()
}
if (rrwebEvents.length === 0) return
uploadFile();
rrwebEvents = []
import pako from 'pako'
// 压缩
const data = "Hello, world!"; // 待压缩的数据
const compressedData = pako.deflate(data); // 使用deflate方法进行压缩
console.log(compressedData); // 输出压缩后的数据 Uint8Array(21) [120, 156, 243, 72, 205, 201, 201, 215, 81, 40, 207, 47, 202, 73, 81, 4, 0, 32, 94, 4, 138]
// 解压
const decompressedData = pako.inflate(compressedData); // 使用inflate方法进行解压缩
const unData = new TextDecoder().decode(decompressedData);
console.log(unData, '解压'); // 输出解压缩后的数据 Hello, world! 解压
// 接口上传文件
function uploadFile() {
console.log('上传文件 ========>>>>>>>>>>>>>>', '\n', rrwebEvents);
fetch('http://localhost:8076/upload', {
method: 'POST',
headers: {
'Content-type': 'application/json'
},
body: JSON.stringify({
rrwebEvents
})
})
.then(response => {
console.log('response', response)
})
.catch(error => {
console.log('error', error)
})
}
// 清除文件
function clearFile() {
fetch('http://localhost:8076/clearFile', {
method: 'POST'
})
.then(response => {
console.log('response', response)
})
.catch(error => {
console.log('error', error)
})
}
function getFile() {
fetch('http://localhost:8076/getFile', {
method: 'POST'
}).then(response => response.json()).then(data => {
new rrwebPlayer({
target: document.getElementById('rrwebplayer'),
data: {
events: data.data,
skipInactive: true,
showDebug: true,
showWarning: true,
autoPlay: true
}
})
})
}
使用node的Koa进行开发简易的服务端,使用文件存储的形式
const Koa = require('koa')
const router = require('koa-router')()
const cors = require('koa-cors')
const bodyParser = require('koa-bodyparser')
const fs = require('fs')
const path = require('path')
const app = new Koa()
app.use(cors())
app.use(bodyParser())
app.use(router.routes())
app.use(async (ctx, next) => {
ctx.set('Access-Control-Allow-Origin', '*')
ctx.set(
'Access-Control-Allow-Headers',
'Content-Type, Content-Length, Authorization, Accept, X-Requested-With , yourHeaderFeild'
)
ctx.set('Access-Control-Allow-Methods', 'PUT, POST, GET, DELETE, OPTIONS')
if (ctx.method == 'OPTIONS') {
ctx.body = 200
} else {
await next()
}
})
router.post('/upload', ctx => {
const jsonFile = path.join(process.cwd(), `./file/jsonFile${Date.now()}.json`)
fs.writeFileSync(jsonFile, JSON.stringify(ctx.request.body.rrwebEvents))
ctx.response.body = {
status: '00'
}
})
router.post('/getFile', ctx => {
const fileDirPath = path.join(process.cwd(), `./file`);
const files = fs.readdirSync(fileDirPath);
let file;
if(files && files.length) {
file = fs.readFileSync(`${fileDirPath}/${files[0]}`);
}
ctx.response.body = {
status: '00',
data: JSON.parse(file)
}
})
router.post('/clearFile', ctx => {
const fileDirPath = path.join(process.cwd(), `./file`);
const files = fs.readdirSync(fileDirPath);
if(files && files.length) {
files.forEach(item => {
const filePath = `${fileDirPath}/${item}`;
fs.unlinkSync(filePath);
})
}
ctx.response.body = {
status: '00'
}
})
app.listen(8076)
console.log('listen on 8076')