前端跨域截图方案(截图通讯)

2021-04-14  本文已影响0人  张力中

本篇是流水账, 后面放出html2canvas源库分析

写在前面

从去年11月份node截图服务遇到问题后,一直在鼓捣前端截图,也逐渐搞出一套自己的前端跨域截图方案,4.13号晚上突破10万张/天,还是挺开心的,当即用puppeteer写了脚本,通知到各个群里哈哈.
放张数量图


前端截图统计.png

目前业务里接入量不到一半,全部走前端截图应该在30万/天左右.

背景

现在做的业务有平台形式的,分享场景,大概是把各个业务方的h5页面,加上二维码生成一张图片,之前一直采用的是node截图服务,(类似phantomjs打开个无头浏览器用浏览器的打印能力生成截图,然后下发给调用方),但是我们这个业务线量太大了,20万b端用户,作业量集中(可参考上面的截图),qps高了,node扛不住.
研究了一下想借助html2canvas的能力, 实现 url -> base64.
给我一个链接,还你一张截图.

技术选型与思考

目前成熟的截图方案中,大概有这几种都能用来搞截图.

  1. 基于node的能力, 最上面那个截图数量就是笔者用puppeteer从统计网站上截的base64,然后调用企微机器人接口进行消息推送. node截图非常简单, 只需要两行
  // 通过浏览器实例 Browser 对象创建页面 Page 对象  - puppeteer为例
  const page = await browser.newPage();
  page.screenshot({
     encode: "base64"
  });

2.基于端能力截图, 找app组的同学用端能力打开一个webview, 然后用端能力的截图方案进行截图,再jsbrige回调给前端.这种笔者认为非常好的一种方案,奈何app组的同学也有技术需求跟kpi,只能从长计议.

3.基于html2canvas截图,github可以搜到html2canvas的库,作者是尼克拉斯,维护很多年,也有很多问题,本质是把全部dom放到canvas里绘制出来, 然后基于canvas的convertToImage能力转成我们需要的base64格式图片.

优势与缺陷

分析一下node截图和html2canvas两种方案

截图方案 优势 缺陷
node截图 1. 截图效果非常好
2.使用范围广,比如小程序内调用接口进行截图
3.追查方便,可以搞事,加几个暗水印还不是分分钟
1.吃服务,qps高了扛不住
2.接口截图需要走流量
3.截图页面需要匿名
4.安全部也要吃饭的,截图页面的外网资源够喝一壶了
html2canvas 1.不占用服务,qps什么的不存在的
2.业务复制性强
3.稳定稳定还是稳定.
1.截图效果普通
2.部分兼容问题,需要手动改html2cavans适应
3.截图速度依赖用户设备
4.不兼容的写法需要开发注意
一图流

流程梳理

最后得出方案如下

  1. 维护一个截图方法, 此方法可以用iframe打开一个跨域的h5, h5链接上有截图标识符,然后开启listening, 等待截图结果的返回
  2. 维护一个sdk, 跨域的业务方在项目中以script的形式引入sdk入口,此入口监听标识符,只会在命中时注入截图脚本,做到无污染.
    3.业务方引入的sdk,会在命中截图逻辑时进行截图,截图会考虑以下内容
    a.监听全部ajax , fetch请求
    b.监听全部图片加载
    c.全部接口与图片加载完毕后,执行截图方法
    d.截图后使用postmessage实现跨域, 并传递截图内容.
  3. 截图成功Y.用截图结果搞事
    截图失败N.走其他截图服务兜底.

其中业务方需要做的事: 引入一行script
平台方需要做的事: 维护截图方法, 此方法接收一个url, return 截图结果.

问题梳理

  1. ios截图文字重叠
    html2canvas 在ios13+上遇到此问题, 在html2canvas测试函数里添加上例子即可,本质是getBoundingRect获取到0,0,0,0.
  2. 超出打点gg
    html2canvas 遇到webkit-box样式发现此问题, 源库未兼容此样式,目前跟inline-block用同样的key来兜底(结果是超出部分没有点,直接被阶段了,还需继续优化)
  3. 文字font-family不对
    依赖设备安装字体,node可以在机器安装,html2canvas无处安放,建议搞font-spider之类加个mini字体包才行.
  4. 文字下沉
    中文font-family遇到此问题, canvas渲染文字的时候,padding-top跟line-height有默认值,目前缩小成以前的1/4感觉良好.
  5. 淘宝rem写法的项目,截图样式有问题
    为了截取高清图,经常会放大截图再缩小,如果rem布局,不要随意更改iframe宽度会导致页面变形,尽量html2canvas去做的时候再动scale.
    6.渐变色
    百度吃现成的吧
    7.伪类元素有问题
    ::after 跟::before 都是用实际dom模拟出来的,所以会进行appendChild的操作,聪明的你一定能猜到,会打乱原有的nth-child(even, odd, first, last)等伪类元素的顺序!
    目前还没有特别好的解决方案, 只能说写法注意吧
    8.object-fit不兼容
    外层套个div, 加上overflow-hidden去写吧,也欢迎有志之士给html2canvas提pr~

...通用型问题后续会继续补充

code

业务代码就不开源了,有疑难杂症可以q群共同解决793841737

总结

使用html2canvas做前端截图真的有点吃力不讨好,
但是这个方案真的是又老又稳健的选择之一,
如果是toC的业务,千万以上的量级,那么我推荐你用前端截图做主方案,服务端截图兜底.
如果是对设计要求特别高的小众业务,那么我推荐你用服务端截图优先,前端截图兜底的方案.

后记

去年因为种种原因,从老东家离职,放弃了美团入职到现在公司,
又赶上结婚,业务调动,半路接手了现在的项目,用了相当多的时间和精力上手,了解业务边界,梳理流程,焦头烂额.
两年前做的vue版的DAG依然有人在使用,前端工程化群里也时不时有新同学加入,同腰间的赘肉一并提醒着:"不能倦怠,多多搞事",然而实在是力不从心.
好在业务慢慢稳定,去年下半年到今年上半年的一些思考,可以慢慢写出来,以供各位同仁阅读,以窥明径,沿辙而行~

上一篇下一篇

猜你喜欢

热点阅读