昨天看到了一篇关于二维码使用的文章,其设计初衷是使用二维码卡片来帮助小朋友控制智能音箱。即在 Raspberry Pi 上使用摄像头来识别二维码,二维码卡片上是一些简单的操作,如播放音乐、暂停等等,卡片的另外一面则是相应的解释。这是一个有趣的二维码在物联网应用的场景。
于是乎,我便想尝试一下直接在云端生成二维码图片,并保存。当然了,对于二维码来说,直接在浏览器上生成显然是更加简单友好的。
总揽
在这个项目里,我们的主要流程是:
从 URL 中获取要生成的二维码字符串
将生成的二维码图片上传到 AWS S3
重定向 URL 到生成的 AWS S3 上
对,就是这么简单,实现起来也很简单。
生成应用
照例我们需要生安装有 serverless
,如果没有的话,请使用:
npm install -g serverless
然后来创建我们的应用:
serverless create --template aws-nodejs --path qrcode
愉快地进行我们的 init commmit。
配置资源
在这个项目里,我们所需要的 AWS 资源有:
AWS S3 用于存储图片
Route 53 用于分配路由
那么,接下来就是打开 serverless.yml
文件进行配置。
resources: Resources: PackageStorage: Type: AWS::S3::Bucket Properties: AccessControl: PublicRead BucketName: ${self:custom.qrcodeBucket} LifecycleConfiguration: Rules: - ExpirationInDays: 1 Status: Enabled
以及配置,相应的权限:
provider: name: aws runtime: nodejs6.10 iamRoleStatements: - Effect: "Allow" Action: - "s3:ListBucket" - "s3:PutObject" - "s3:PutObjectAcl" Resource: - "arn:aws:s3:::${self:custom.qrcodeBucket}" - "arn:aws:s3:::${self:custom.qrcodeBucket}/*"
还有 Route 53 中的域名:
plugins: - serverless-domain-manager custom: # change this, so it's unique for your setup qrcodeBucket: ${self:service}.${self:provider.stage,opt:stage} stageVariables: bucketName: ${self:custom.qrcodeBucket} customDomain: domainName: qrcode.pho.im basePath: '' stage: ${self:provider.stage} createRoute53Record: true
接下来,就可以愉快地写代码了。
生成二维码
为了生成二维码,我找到了项目:node-qrcode,然后安装之:
yarn add qrcode
试了试 DEMO:
QRCode.toFile('path/to/filename.png', 'Some text', { color: { dark: '#00F', // Blue dots light: '#0000' // Transparent background } }, function (err) { if (err) throw err console.log('done') })
不对,这样好像有问题:
QRCode.toDataURL(string, { errorCorrectionLevel: 'H' }, function (err, url) { }
在尝试了多次之后,我手动将 base64 转成了 png:
new Buffer(url.replace(/^data:image\/\w+;base64,/, ""), 'base64')
随后,就可以上传图片了 AWS S3 上。
上传 AWS S3
只需要配置好相应的权限和 Key、Bucket,然后使用 ContentEncoding 为 base64:
const params = { Bucket: process.env.bucketName, Key: key, ACL: 'public-read', Body: new Buffer(url.replace(/^data:image\/\w+;base64,/, ""), 'base64'), ContentEncoding: 'base64', ContentType: 'image/png'}; s3.putObject(params, function (err, data) { if (err) { return callback(new Error(`Failed to put s3 object: ${err}`)); } const response = { statusCode: 302, headers: { location: `https://s3.amazonaws.com/${process.env.bucketName}/${key}` } }; return callback(null, response); })
将 ACL 配置为 public-read,就可以在外网访问了。
优化二维码
在多次测试之后,我决定优化一下上传的参数:
QRCode.toDataURL(string, { errorCorrectionLevel: 'H', width: 512, margin: 2, color: { light: '#fdfdfd', dark: '#384452' } }
部署及测试
好了,现在我们就可以部署,执行相应的部署命令:
$ sls deploy Serverless: Packaging service... Serverless: Excluding development dependencies... Serverless: Uploading CloudFormation file to S3... Serverless: Uploading artifacts... Serverless: Uploading service .zip file to S3 (699.08 KB)... Serverless: Validating template... Serverless: Updating Stack... Serverless: Checking Stack update progress... .............. Serverless: Stack update finished... Service Information service: qrcode stage: dev region: us-east-1stack: qrcode-dev api keys: None endpoints: GET - https://swsaner181.execute-api.us-east-1.amazonaws.com/dev/ functions: create: qrcode-dev-createServerless Domain Manager SummaryDomain Name qrcode.pho.im Distribution Domain Name d1vpwj4ctk345u.cloudfront.net Serverless: Removing old service versions...
然后在网页上测试,我们创建的服务地址是:https://qrcode.pho.im/?q={string}
使用这个 URL 进行测试:https://qrcode.pho.im/?q=http://weixin.qq.com/r/mnVYQHrEVicprT4j9yCI
加上使用的短链服务就是:https://x.pho.im/Z5t7