实现一个 Code Pen:(六)云函数生成网页缩略图

sxkk20081年前知识分享117

前言

在前面的文章中,我们已经实现了编辑器的功能,并且数据可以保存到云数据库,接下来我们需要生成缩略图的功能,目前掘金的的 code pen 还没有缩略图的功能,这是否是一个挑战呢?

缩略图生成方法

生成缩略图的方法可分为 2 种,一种是客户端生成,还有一种是服务端生成。

dom-to-img

客户端生成我第一个想到的是使用到一个库 dom-to-img

这个库,其主要原理是:

  • 将 html node 转化为 xml,设定命名空间

  • foreignObject 包裹 xml

  • 把内容变为了 svg

  • svg 变为 base64 的图片

    下面代码是最核心的源码中的一个函数 makeSvgDataUri

function makeSvgDataUri(node, width, height) {
  return Promise.resolve(node)
    .then(function (node) {
      node.setAttribute('xmlns', 'http://www.w3.org/1999/xhtml')
      return new XMLSerializer().serializeToString(node)
    })
    .then(util.escapeXhtml)
    .then(function (xhtml) {
      return '' + xhtml + ''
    })
    .then(function (foreignObject) {
      return (
        '' +
        foreignObject +
        ''
      )
    })
    .then(function (svg) {
      return 'data:image/svg+xml;,' + svg
    })
}

使用这个库的好处是可以通过客户端生成,节省服务端资源。但不足的是用户的浏览器大小不一,所生成的图片大小也不一样, 所以在我们 code pen 缩略图场景中,客户端生成不合适。

Puppeteer

服务端生成缩略图,我想到的是使用 Puppeteer 生成网页截图,来到达生成缩略图的效果。

Puppeteer 可以将 Chrome 或者 Chromium 以无界面的方式运行(当然也可以运行在有界面的服务器上),然后可以通过代码控制浏览器的行为,即使是非界面的模式运行,Chrome 或 Chromium 也可以在内存中正确渲染网页的内容。

vercel

由于我使用的是 vercel 部署的,那么我们是否可以使用 vercel 来生成缩略图吗?

我在一顿搜索之后找一篇文章 《Generate Open Graph images on-demand with Next.js on Vercel》

核心代码如下。

import chromium from 'chrome-aws-lambda'
import playwright from 'playwright-core'

const getAbsoluteURL = (path) => {
  const baseURL = process.env.VERCEL_URL
    ? `https://${process.env.VERCEL_URL}`
    : 'http://localhost:3000'
  return baseURL + path
}

export default async function handler(req, res) {
  // Start the browser with the AWS Lambda wrapper (chrome-aws-lambda)
  const browser = await playwright.chromium.launch({
    args: chromium.args,
    executablePath: await chromium.executablePath,
    headless: chromium.headless,
  })
  // 创建一个页面,并设置视窗大小
  const page = await browser.newPage({
    viewport: {
      width: 1200,
      height: 630,
    },
  })
  // 从url path 拼接成完成路径
  const url = getAbsoluteURL(req.query['path'] || '')
  await page.goto(url, {
    timeout: 15 * 1000,
    waitUntil: 'networkidle',
  })
  await page.waitForTimeout(1000)
  // 生成png 的缩略图
  const data = await page.screenshot({
    type: 'png',
  })
  await browser.close()
  // 设置图片强缓存
  res.setHeader('Cache-Control', 's-maxage=31536000, stale-while-revalidate')
  res.setHeader('Content-Type', 'image/png')
  // 设置返回 Content-Type 图片格式
  res.end(data)
}

chrome-aws-lambda 是为了 serverless 环境定制的 chrome 内核,包大小比较小,我将这段代码部署上去,通过 url 拼接的方式访问,我们就可以生成当前页面的缩略图了;

大家可以通过 https://code.runjs.cool/api/thumbnail?path=/pen/create 这个地址访问体验。 虽然有点慢,但是可以生成缩略图

vercel 生成的缩略图

有个问题就是,右上角的“保存”无法显示,查了下github chrome-aws-lambda 不包含任何字体,所以要支持中文,先要加载中文字体

readme 中有 demo

await chromium.font('/var/task/fonts/NotoColorEmoji.ttf')
// or
await chromium.font('https://raw.githack.com/googlei18n/noto-emoji/master/fonts/NotoColorEmoji.ttf')

字体可以下载阿里巴巴普惠体,由于中文字体比较大,我就没有尝试,既然速度慢,那能否试试国内的云环境呢?

uniapp

由于我使用的云存储是 uniapp,那么我将尝试下 uniapp 的云函数。

本地尝试

于是我建立了一个云函数,然后在本地运行云函数。

首先安装使用 npm 安装 puppeteer npm i puppeteer

输入云函数代码

const puppeteer = require('puppeteer')

exports.main = async (event, context) => {
  const browser = await puppeteer.launch()
  const page = await browser.newPage()
  await page.goto('https://baidu.com')
  const path = `${__dirname}/img.png`
  await page.screenshot({ path })
  await browser.close()
  return 1
}

执行完成后就在本地生成img.png文件,效果如下图

puppeteer 百度首页截图

没错,生成的是一张800*600 大小的浏览器截图,感觉没问题了。

阿里云

于是我就按这个逻辑写完了云函数,当我点击上传部署 的时候,HbuildX 就没有进度,一直处于上传中,查了下资料,应该是 puppeteer 本身依赖了 Chromium,Chromium 又依赖非常多的系统库,无法在云函数上安装完成。

但是我在阿里云官网找到了一篇文章

《Serverless 实战 —— 快速开发一个分布式 Puppeteer 网页截图服务》

按这篇文章讲述的是阿里云是支持 Puppeteer,由于 puppeteer 比较大,云函数会自动开通 NAS 服务(文件存储)

所以 uniapp 中选择服务商选择阿里云,云函数式不支持 puppeteer 的

腾讯云

那么腾讯云支持吗?后来我又查到腾讯云云函数中内置了 puppeteer,可以在文档中找到,注意(nodejs 16)已经不支持 puppeteer

于是我又尝试了腾讯云函数,代码如下

const puppeteer = require('puppeteer')

exports.main = async (event, context) => {
  const browser = await puppeteer.launch({
    headless: true,
    args: ['--no-sandbox', '--disable-setuid-sandbox'],
  })
  const page = await browser.newPage()
  await page.goto('https://baidu.com')
  const res = await page.screenshot()
  await browser.close()

  return {
    isBase64Encoded: true,
    statusCode: 200,
    headers: {
      'content-type': 'image/png',
      'Cache-Control': 's-maxage=31536000, stale-while-revalidate',
    },
    body: res.toString('base64'),
  }
}

此时不需要 package.json,上传后,云函数 URL 化,

体验地址:

https://tcb-mtsm4smjc8dbf7-8dkm6932475ab.service.tcloudbase.com/baidu

效果

腾讯云函数 puppeteer 缩略图

应该是满足了我们的需求。

小结

本文介绍了生成缩略图的方式

  1. dom-to-img 客户端生成,但是用户的浏览器大小不一,缩略图大小不一样。

  2. vercel 可以配合 chrome-aws-lambda 可以生成缩略图,但是必须要先加载字体。

  3. uniapp 免费的阿里云函数不支持 Puppeteer,可以直接使用阿里云的 serverles 服务,但是要开通 NAS。

  4. 腾讯云函数系统内置 Puppeteer,免安装,应该是比较不错的方案。

最后贴一下我项目地址和代码

预览地址:https://code.runjs.cool/pen/create

代码仓库:https://github.com/maqi1520/next-code-pen

以上就是本文全部内容,希望这篇文章对大家有所帮助,也可以参考我往期的文章或者在评论区交流你的想法和心得,欢迎一起探索前端。

本文首发掘金平台,来源Ai知识分享博客

相关文章

AI技术的发展与应用-探索人工智能的新未来

AI技术的发展与应用-探索人工智能的新未来

   人工智能(AI)在20世纪50年代开始被提出,如今在技术和应用上取得了巨大的进步,得到了各行各业的应用。随着数据和算力的爆发式增长,我们正在看到AI技术的未来发展将更加...

热门AI技术探索-从“眼球跟踪”到“生成对抗网络”

热门AI技术探索-从“眼球跟踪”到“生成对抗网络”

  AI技术近年来得到了飞速发展,在各领域都有广泛应用。本文就以“眼球跟踪”技术和“生成对抗网络”技术为代表,探寻当前AI技术的热门方向和发展趋势。  一、“眼球跟踪”技术 ...

AI技术培训:培养未来人工智能领域专业人才

AI技术培训:培养未来人工智能领域专业人才

  人工智能(AI)如今已经成为全球热门话题。从制造业、医疗保健到教育领域,AI技术已经开始对人们的生产和生活产生积极影响。然而,真正掌握AI技术的工程师人才并不多,这意味着...

人工智能赋能——探索easydl平台在机器学习领域的应用与前景

人工智能赋能——探索easydl平台在机器学习领域的应用与前景

  近年来,随着人工智能技术的快速发展,机器学习成为了研究的热点。easydl平台作为一种强大的人工智能平台,为机器学习领域带来了许多新的机遇和挑战。本文将探索easydl平...

AI人工智能:改变未来的无限可能

AI人工智能:改变未来的无限可能

  随着科技不断地向前发展,AI人工智能也越来越成为当今社会的热门话题。人工智能是一项能够模拟人类智能思维的技术,它可以对数据进行自动分析和处理,并通过机器学习实现自我学习和...

AI绘画:当机器学习遇上创意

AI绘画:当机器学习遇上创意

  在过去的几十年里,人工智能一直是科技领域中备受关注的热门话题之一。随着技术的不断进步,AI也逐渐融入了我们的生活,成为了我们工作、学习和休闲的重要工具和娱乐手段。而AI绘...

发表评论    

◎欢迎参与讨论,请在这里发表您的看法、交流您的观点。