我是如何把满足监管需求的视频可回溯完整系统一步一步做出来的

一、 项目背景

保险、基金、银行等众多行业在做技术平台时都会需要一种能够准确了解用户操作行为的方式方法。诸如通过埋点、平台监控、视频可回溯等,通过技术手段,保存用户操作轨迹,以此规范安全销售、平台健康检查、出现纠纷时可追溯、问题出现有证据。 为规范保险行业销售行为,zf出台相关政策:

了解政策原文

在本人开发系统之前,全网似乎也有几家公司已经在推广销售双录系统,但是介于价格较高,且本人有兴趣挑战这种比较大型的平台系统。对未知领域充满无限好奇心的驱动力使我一步一步将一套完整的视频可回溯项目比较完整的实现了。在此先给自己鼓个掌!👍👍😁

二、前期准备

行业研究:

  • 怎么将用户在web前端应用(pc端、h5移动端等)的操作轨迹通过视频的形式保存下来可以说是一个比较难实现的技术要求。
  • 最初想法:寻找录屏插件、通过轮询截图,最后生成视频、等等不太可行的方案都想过。后来经过各种问度娘,搜github, 技术论坛;
  • 最终锁定到了github一个非常优秀的开源框架rrweb上。一句话,这个框架核心思想就是,将用户操作的行为通过mutationObseverjs原生方法将dom按照时间顺序保存成对象数组,数组里是包含唯一的dom、value、事件等。实现原理可以看这篇文章戳这里

功能要素:

  • 该开源框架提供了核心部分,但是怎么利用这个底层框架,开发一套完整的系统也是一件不简单的事;

  • 该系统需要包含以下几个大模块:

    1. 放在web项目的录屏sdk(应具备无代码浸入方式接入)
    1. 需要一套后台管理系统,分为前端界面和后端服务
    1. 数据存储方法论,数据治理、数据清洗等
    1. 系统应具备安全稳定,方便部署应用的能力

技术方案:

  • 本人前端出身,对宇宙后端第一大语言Java学习的还不够,自知学海无涯、无心无力边学边用,java就果断放弃。
  • 选择了同样优秀但是目前仍然比较新的后端开发框架tegg, tegg是eggjs的升级版本,加入了ts元素和注解方式,约定优于配置是其灵魂,加入respository我认为是最好用的,扯远了。
  • 技术核心如下:
  • 探针sdk(录屏)(vue3+ts+vite+pako+loadsh-es等,也包括打包所用工具css、js文件注入,js混淆加密等)
  • 后端管理系统(前端)(vue2+ant-design-vue+vue全家桶+rrweb+loadsh+store等)
  • 后端管理系统(后端)(tegg框架相关+ali-oss+mysql+egg-redis+pako+puppeteer+rrweb+rrweb-player等)
  • 项目管理:本项目采用pnpm monorepo微前端管理体系。eslint+pretter+commitlint提交规范配置+stylelint样式规范等前端基础工程化配置。
  • 存储:使用mysql数据库+redis缓存数据库+阿里云oss永久存储
  • 部署:采用Dockerfile及docker-compose.yml配合docker容器部署
  • 发布:使用jenkins代码发布工具+gitee版本仓库
  • 服务器: 云服务器

三、 项目开发

1. 录屏sdk

  • sdk应具备的能力:

    1. 视频文件events的收集上报

    2. sdk鉴权方式

    3. sdk与使用方业务关联(例如,绑定订单id,通过订单id查询此视频)

    4. 业务方需主动触发结束录屏动作

    5. 需要配置业务web哪个页面需要录屏

    6. 功能上考虑节流防抖,click、scroll、keyup页面事件操作时的上报策略等

  • sdk服务于sdk探针:

    1. 本项目使用sdk与sdk服务(node)相互配合达到一行代码注入使用的能力。
    2. js混淆加密使项目更加安全。
css 复制代码
<script defer src="http://127.0.0.1:8085/snail_record_wr_start?id='6c9415b0db6811eeb301858cecb0709b'&source='时光机可回溯系统'&version='2.0.0'"></script>

2. 后端管理系统

- 功能模块:

markdown 复制代码
-  权限管理:菜单管理、角色管理、用户管理
-  可回溯管理:商户配置、录屏配置、视频列表、视频播放、sdk版本管理
    

- 后端核心

项目采用tegg微服务方式,权限模块,公共模块,录屏模块,html模版view模块

最最核心是如何存储视频文件数据,思想和方法论是最关键的,前端只要用户操作每隔1s调一次接口,然后后端保存缓存文件。 本项目采取三段式分片定时任务处理数据存储,合并和压缩上传功能。

在不频繁处理数据库操作的基础思想下,定时任务分批处理。

这个地方,想了比较久,甚至过年开车回家,在路上就一直在想方案,也没想出来,年后回来,在某一刻想通了哈哈哈。就是这么神奇

贴一段核心代码

js 复制代码
/**
** @Author: wangke
** @Date: 2024/02/08 20:03:59
** @Description: 查询videoProgress=2时 将 screenRecordVideos 视频txt文件压缩归档,场景就是,用户在订单完成后,迟迟没有支付,或者,很长时间才到达结束页,这时,结束页要再次归档
*/
async scheduleVideoFileZip(searchParams, type: number) {
  const videoPath = this.config.recordEventDir + Constant.SCREEN_RECORD_VIDEO_DIR
  const fileArr = zipFileFunc(videoPath)
  setTimeout(async () => {
    const deviceIdArr = []
    if (!fileArr.length) return false
    for (let i = 0; i < fileArr.length; i++) {
      deviceIdArr.push(fileArr[i].split('.')[0] as never)
    }
    // 查找数据,然后将zip文件归档云存储
    searchParams = { deviceId: deviceIdArr, ...searchParams } // 当数据库里有设备id时才存到oss上,避免脏数据归档
    const videoList = await this.VideoListRepository.queryAll(searchParams)
    if (videoList.length <= 0) return
    for (let i = 0; i < videoList.length; i++) {
      const txtFileName = videoList[i].deviceId + this.config.video_file_suffix
      const zipFileName = videoList[i].deviceId + this.config.video_zip_file_suffix
      const txtFileInfo = this.config.recordEventDir + Constant.SCREEN_RECORD_VIDEO_DIR + txtFileName
      const fileInfo = this.config.recordEventDir + Constant.SCREEN_RECORD_VIDEO_DIR + zipFileName
      if (await isExistFileFunc(txtFileInfo)) {
        await Oss.ossPut('zip/' + dateFileDirFunc() + zipFileName, fileInfo)
        const videoSize = getFileSize(fileInfo)
        let videoParams = {
          videoSize,
          videoStatus: Constant.VIDEO_HAVE_MAKE,
          videoUrl: 'zip/' + dateFileDirFunc() + zipFileName,
          // videoUrl: ossRes.url
         videoProgress: ''
        }
        if (type === 2) {
          videoParams = { ...videoParams, videoProgress: '3' }
        }
        const updateRes = await this.VideoListRepository.update(videoList[i].deviceId, videoParams)
        if (updateRes) {
          fsync.unlinkSync(fileInfo)
          type === 2 && fsync.unlinkSync(txtFileInfo)
        }
      }
    }
  }, 1000)
}

四、 项目打包

  • sdk通过vite打包成可插拔式的插件,并且进行加密处理
  • 时光机后管系统前端用vue-cli脚手架打包
  • 后管的服务端使用egg eggctl
  • 每个单独项目使用docker 部署

五、项目部署

  • 云服务器

六、项目架构图

有感兴趣的小伙伴点个赞,关注下, 下期针对项目代码具体实现进行详细解剖,欢迎点赞评论。一起成长,一起进步,一起探索大前端等技术。

远离喧闹的城市,远离熙攘的人群,沉浸在代码的海洋里,忘乎所以地在自己的世界里狂欢。

相关推荐
Devil枫4 小时前
Vue 3 单元测试与E2E测试
前端·vue.js·单元测试
GIS程序媛—椰子5 小时前
【Vue 全家桶】6、vue-router 路由(更新中)
前端·vue.js
前端青山5 小时前
Node.js-增强 API 安全性和性能优化
开发语言·前端·javascript·性能优化·前端框架·node.js
毕业设计制作和分享6 小时前
ssm《数据库系统原理》课程平台的设计与实现+vue
前端·数据库·vue.js·oracle·mybatis
程序媛小果6 小时前
基于java+SpringBoot+Vue的旅游管理系统设计与实现
java·vue.js·spring boot
从兄7 小时前
vue 使用docx-preview 预览替换文档内的特定变量
javascript·vue.js·ecmascript
凉辰7 小时前
设计模式 策略模式 场景Vue (技术提升)
vue.js·设计模式·策略模式
GDAL8 小时前
npm入门教程1:npm简介
前端·npm·node.js
薛一半9 小时前
PC端查看历史消息,鼠标向上滚动加载数据时页面停留在上次查看的位置
前端·javascript·vue.js
MarcoPage9 小时前
第十九课 Vue组件中的方法
前端·javascript·vue.js