前言:在前端日常开发中,toC的业务难免会有一些截图或者生成海报的业务需要受限于html2canvas的不兼容性,或者canvas画图的款式局限性,目前咱们又有了一种新的解决方案,node + puppeteer的组合,
puppeteer
puppeteer 初识
Puppeteer 是 Google Chrome 团队官网的无界面(Headless)Chrome 工具。Chrome 作为浏览器市场的领头羊,Chrome Headless 将成为 web 利用 自动化测试 的行业标杆
那么咱们能够用puppeteer来些什么?
- 生成页面的截图或者PDF
- 主动模仿用户行为,表单提交、按钮点击等
- 创立自动化测试环境
- 捕捉站点的工夫线跟踪,以帮忙诊断性能问题。
- 爬取 SPA 页面并进行预渲染(即'SSR')
可见第一种个性正式咱们用的到的
puppeteer 装置
npm install puppeteer// 下载内核步骤可能会失败,cnpm 或迷信上网
puppeteer 次要api
只介绍截图相干,如果须要其余个性的查问,请移步:https://github.com/puppeteer/...
1.启动实例
import * as puppeteer from 'puppeteer'(async () => { await puppeteer.launch()})()
2.网页截图
png截图
await page.setViewport({width, height}) await page.goto(url) //对整个页面截图 await page.screenshot({ path: path.resolve(`./screenshot/${fileName}.png`), //图片保留门路 type: 'png', fullPage: false //边滚动边截图 })
不仅如此 还能够模拟手机的device环境
import * as puppeteer from "puppeteer";import * as devices from "puppeteer/DeviceDescriptors";const iPhone = devices["iPhone 6"];(async () => { const browser = await puppeteer.launch({ headless: false }); const page = await browser.newPage(); await page.emulate(iPhone); await page.goto("https://baidu.com/"); await browser.close();})();
pdf截图
(async () => { const browser = await puppeteer.launch(); const page = await browser.newPage(); await page.goto("https://example.com/"); await page.pdf({ displayHeaderFooter: true, path: 'example.pdf', format: 'A4', headerTemplate: '<b style="font-size: 30px">Hello world<b/>', footerTemplate: '<b style="font-size: 30px">Some text</b>', margin: { top: "100px", bottom: "200px", right: "30px", left: "30px", } }); await browser.close();})()
好~有了这些咱们就能够满足咱们根本截图需要了
根本架构
阐明
截图申请接口:此api会间接申请到 node 服务,会携带参数包含:
- 托管页地址 (为要截取网页的地址)
- 要截图的宽高
- 截图的类型 (png/pdf)
截图托管页:动态的html页面。可url传参数去控制变量
node服务收到接口申请后,会申请托管页,构建一个要截取的网页,执行截图操作的api,返回截图buffer数据给申请的接口,到此为止,咱们基础架构就整顿结束了
上 demo 代码
前置环境,假如咱们当初曾经有一个可用的node环境(node + koa2)
// router层const screenshotControllers = require('../controllers/puppeteer')const router = new KoaRouter()exports.router = router.post('/api/puppeteer/v1/screenshot', screenshotControllers.api.screenshot)
// conteoller层const service = require('../service/puppeteer')const screenshot = (ctx, next) => { return service.api.screenshot(ctx);}exports.api = { screenshot}
// service层const { getScreenshot } = require('../puppeteer/index')exports.api = { screenshot: async (ctx) => { const { width, height, url, tid} = ctx.request.body const res = await getScreenshot(url, width, height, tid) console.log(res) if (res) { ctx.body = { code: 200, message: '胜利', data: res } } }}
//具体业务层const puppeteer = require('puppeteer');const path = require('path')exports.getScreenshot = async (url, width = 800, height = 600, fileName) => { const browser = await puppeteer.launch() const page = await browser.newPage() //设置可视区域大小,默认的页面大小为800x600分辨率 await page.setViewport({width, height}) await page.goto(url) //对整个页面截图 await page.screenshot({ path: path.resolve(`./screenshot/${fileName}.png`), //图片保留门路 type: 'png', fullPage: false //边滚动边截图 }) //执行cos 或 oss 脚本,把图片上传到cdn环境,此处因为调试,临时省略 await page.close() await browser.close() return `${fileName}.png`}
测试服务可用性
启动 node 服务
启动 psotman 模仿申请接口
1.百度
查看后果
2.掘金
{ "url": "https://juejin.cn/", "width": 720, "height": 1080, "tid": 0}
嗯,看起来也没啥问题
具体业务利用
目前有生成海报的需要,那么咱们应该怎么搞?
1.依据UI图,搞定托管页
2.依据传入的变量id,写好后端逻辑,
3.调用node服务,取得图片buffer 或图片cdn地址
await axios({ method: 'POST', url: 'http://xxx/api/puppeteer/v1/screenshot', data: { url: `http://xxx/postFrame/home?lecCode=lec${i}`, width: 335, height: 525, tid: `lec${i}` } })
至此就大功搞成了,这种解决方案能够磨平各种运行环境的差异性,缩小本地生成图片的失败率