1. 背景

微信小程序现可接入物流[1],实现下单、打单和物流跟踪等功能。对于打单功能,微信提供了几种不同的接入方式,如windows only的打单软件或需要额外接入的第三方打单软件,否则需要通过getOrder接口获取数据自行打印[2]。getOrder接口会返回base64编码的运单html页面,直接在浏览器中渲染出来打印会遇到的最主要的问题是浏览器的兼容性,可通过使用可控的浏览器渲染出页面再保存为图片的方式解决。在这方面puppeteer[3]可以说是首选。

快递单

需渲染的快递单

不过puppeteer也有自己的问题。比如现在的后端大多是以容器方式部署的,而配置puppeteer在容器中运行并不方便[4],且配置不当可能有潜在的安全风险。恰逢最近在调研FaaS,就想着既然serverless方式部署可以不关心服务器,是不是就能转嫁掉风险了?

2. 问题调研

puppeteer运行需要Node.js。根据腾讯云的文档[5],Node.js应用需要将依赖库一同打包上传。由于puppeteer依赖了Chromium,就意味着需要在CentOS下安装一个Chromium并打包上传,否则很容易因为环境不一致而出问题。好在腾讯云的Node.js环境[6]已经内置了puppeteer,部署时就不用再上传了。

不过在本地还是需要安装puppeteer,否则就无法在本地调试了。那么在部署时如何才能不上传本地安装的puppeteer呢?根据serverless的约定,只要把puppeteer作为devDependencies安装,使用serverless命令行部署时就会被自动忽略,不会被打包进去了。

3. 开发

开发没有什么难度,基本上只要把puppeteer和腾讯云云函数各自最简单的sample连起来就可以。值得注意的是腾讯云云函数对函数入口的形式有规定[7],可以说是种提供商绑定,如果要解除绑定的话就需要至少多加一层抽象。

4. 部署

使用serverlesss命令行生成的默认serverless.yml中没有指定网关,api网关触发器的serviceId为空

    events:
      - apigw:
          parameters:
            stageName: test 
            serviceId:
            httpMethod: ANY

这就会导致每次部署时均创建一个新的网关,访问链接也会发生变化。可以在第一次部署后把创建的网关的serviceId填回serverless.yml中(或是部署之前先自己手动在腾讯云的控制台创建一个API网关),这样就能复用这个网关,访问地址也不会变,生产环境中也可以直接用作反向代理的上游。

在线调试时依旧遇到了常见的No usable sandbox!错误[8]。鉴于是serverless环境无法配置服务器,只能以无沙盒方式启动。相信腾讯云应该有足够的安全措施🐶

5. 其他问题

5.1 TypeScript

当前JavaScript后端开发基本都会采用TypeScript,而腾讯云的sample还都是JavaScript的。其实用TypeScript开发云函数很简单,只需确保tsc编译的输出目录中包含云函数所需的文件即可。通过一个简单的脚本就可以搞定:

# 编译.ts文件,输出到 dist/ 目录
$ npm run build

# 复制 package.json 和 package-lock.json
$ cp package* dist/

# 复制 serverless.yml
$ cp serverless.yml dist/

$ cd dist

# 只安装 production 依赖
$ npm ci --only=production

# serverless 部署
$ sls deploy

5.2 使用Web框架

上面提到,由于腾讯云对于云函数的函数入口有要求,对于已有的项目可能就需要迁移,而迁移的结果可能就是提供商绑定。理想的情况下,现有的功能应该能在不同的云提供商之间无缝迁移。目前已经有些项目提供了常见的Web框架如Expresskoa的支持,有时间的话会继续实践。

update: 后续在这里

6. 小结

实际用下来的感觉,FaaS比较适合的场景是:

  • 对响应延迟要求低
  • 并发量不大
  • 调用次数不多
  • 无状态

像上面提到的网页转图片的服务就是这样的例子。一个企业内部可能有大量像这样的长尾服务,使用量小,使用周期短,却依旧需要和头部的服务一视同仁地进行部署和维护。如果采用FaaS的话开发者自己就能很方便地进行部署,从而节省大量运维资源。此外云服务商通常都提供了充沛的免费额度,这样部署和使用云函数基本就是在白嫖了。

p.s. puppeteer经常被用来做爬虫,而在腾讯云的文档中写着,云函数的出口IP在默认情况下是随机的[9]。这意味着什么还需要观察🐶

参考资料