无头浏览器 from wikipedia: A headless browser is a web browser without a graphical user interface。无头实际上是指无界面地运行浏览器
我们在终端或者代码层,使用无头浏览器的技术来可以模拟用户在网页端的浏览及操作。
一、无头浏览器的相关应用
- E2E 测试:无需打开UI界面,即可完成对应的测试内容。模拟表单提交,键盘输入,点击等行为
- 网络爬虫 、SSR 服务端渲染
- 网页截图生成海报或 PDF
- 捕获网站时间线,帮助诊断性能问题(Lighthouse 就是使用了无头浏览器的技术的性能测量工具,他可生成各种性能数据以及网页加载时的快照,以辅助前端做一些性能优化
以上,无头浏览器的作用非常强大;今天就以 posterMan 这个比较简单但是很有代表性的服务,来讲一下在前端的具体应用。
二、posterMan 简介
类似于网抑云音乐,知乎的划线笔记。用户在截屏时可以生成封面海报。
posterMan 是一个 Node 服务。当我们提供一个 url 链接给到 posterMan 时,即可生成相应的封面截图。
2.1 海报生成链路
2.2 Puppteer 相关介绍
译:木偶;基于 CDP(Chrome devtools-protocol) 封装的 Node 库
原理:
- 基于 WebSocket,利用 WebSocket 实现与浏览器内核的快速数据通道;
- CDP 分为多个域,每个域中都定义了相关的命令和事件(Commands and Events);
- 基于 CDP 封装一些工具对 Chrome 浏览器进行调试及分析。
2.3 Puppeteer VS Phantomjs
puppeteer | phantomjs | |
---|---|---|
环境依赖 | 依赖 Node | Linux: GLIBCXX_3.4.9 和 GLIBC_2.7 |
更新进度 | 持续更新(V1.8) | 停止更新(V2.1) |
JavaScript 标准 | 新的ES 标准 | ES5 |
整体优点 | 持续更新,功能性能可期 | 部署快捷方便,基本上达到了开箱即用 |
使用新ES标准,对异步事件处理更简便 | 脚本语言更适合原生开发,学习成本低 | |
支持chrome插件 | ||
整体缺点 | 部署相对复杂,且需要翻墙 | 已经停更 |
Java 端调用仍需使用 CMD 和 Shell 调用,Node 端可直接使用 | 只能通过 CMD 和 Shell 调用 | |
开放的 api 较少, 且调试过程复杂 |
2.4 Puppeteer 模拟用户操作
2.5 链接池 Generic pool
当用户访问调用 posterMan 时,就会创建一个 Puppteer 的实例子,但是当我们的服务访问量巨大的时候,频繁的创建和销毁连接会产生非常大的系统开销。这个时候,链接池 Generic pool 就隆重登场了。
2.5.1 线程池-合理配置
- 合理设置连接池数;posterMan 阈值(min:2;Max:10);
- 尽可能利用缓存,减少对数据库的查询;
- 使用完一个数据库连接后,尽快释放给管理池。
三、纯前端实现
3.1 利用CanvasAPI (html2Canvas)
- 递归取出目标模版的所有 DOM 节点,填充到一个 rederList,并附加是否为顶层元素/包含内容的容器 等信息
- 通过 z-index postion float等css属性和元素的层级信息将 rederList 排序,计算出一个 canvas 的 renderQueue
- 遍历 renderQueue,将 css 样式转为 setFillStyle 可识别的参数,依据 nodeType 调用相对应 canvas 方法,如文本则调用 fillText,图片 drawImage,设置背景色的 div 调用 fillRect 等
- 将画好的canvas填充进页面
缺点:
- 无法渲染跨域资源(支持同域)
- 无法渲染 iframe和 Flash 内容
- 大量的递归和计算会非常缓慢
3.2 SVG
- 首先,我们要声明一个基础的svg模版,这个模版需要一些基础的描述信息,最重要的,它要有
这对标签 - 将要渲染的 DOM 模版模版嵌入 foreignObject
- 利用 Blob 构建 SVG 图像
- 取出 URL
一个最为严肃的问题在于:SVG 无法加载外部资源,也就是说,在 SVG 里面,无论是还是 或者 CSS 中的背景图, 这些资源都是无法加载的。在使用 canvas 实现时,因为我们使用 Node 去绘制,所以不存在资源引用的问题。但使用 SVG 实现,相当于我们把文档交给 SVG 再来渲染,这对于我们来说是其实是无法控制的黑盒操作,是受 SVG 限制的。