批量生成100萬張小程式碼?瞭解一下。

最近有一個生成很多小程式碼的需求,生成的小程式碼還要嵌入在指定的圖片模板上,就去找輪子,沒找到合適的輪子。。無奈之下就決定去擼一個。目前已經完成併發布npm。
Github: ofollow,noindex">github.com/Jon-Millent…
需求
如下圖

- 生成帶引數的小程式二維碼
- 要指定尺寸和位置到模板圖上
- 要批量生成若干張
開始幹活
生成帶引數的小程式二維碼
通過官方文件,列出了生成小程式二維碼的三種模式
-
createWXAQRCode
獲取小程式二維碼
,適用於需要的碼數量較少的業務場景。通過該介面生成的小程式碼,永久有效,有數量限制。官方說明 -
getWXACode
獲取小程式碼
,適用於需要的碼數量較少的業務場景。通過該介面生成的小程式碼,永久有效,有數量限制。官方說明 -
getWXACodeUnlimit
獲取小程式碼
,適用於需要的碼數量極多的業務場景。通過該介面生成的小程式碼,永久有效,數量暫無限制。官方說明
這些介面都要通過 access_token
來換取。讓我們造個類
let AngerWechat = require('anger-wechat') // 微信操作輔助庫(自己寫的) class miniQrcode { // 存放三種模式的介面 constructor(config) { this.mode = { 'getWXACode': 'https://api.weixin.qq.com/wxa/getwxacode', 'getWXACodeUnlimit': 'https://api.weixin.qq.com/wxa/getwxacodeunlimit', 'createWXAQRCode': 'https://api.weixin.qq.com/cgi-bin/wxaapp/createwxaqrcode', } // 初始化微信輔助庫 this.$wx = new AngerWechat({ appId: this.config.appId, // appId 必傳 appSecret: this.config.appSecret, // appSecret 必傳 }) // 臨時資料存放檔案,用於存放access_token,因為access_token有2個小時的生存期,避免重複獲取 this.databasePath = path.join(__dirname, '../', 'database.json') } } 複製程式碼
實現核心方法
// 生成核心方法 async getWxQrcodeInfo(concatConfig){ // 獲取已經存放的檔案裡的access_token,如果有的話並且有效的話就不用再掉介面 let innerDatabase = this.getDatabase() // 如果本地的資料沒有access_token 或者超過2個小時 就去請求獲取 if(!innerDatabase.access_token ||((new Date().getTime() - innerDatabase.create_time) > 7200000) ) { let accessInfo = await this.$wx.getGlobalAccessToken() // 獲取access_token然後寫入檔案 // 具體程式碼省略 } // 獲取到access_token去請求介面 let qrcodeInfo= await this.postMan( this.getApiUrl(innerDatabase.access_token, concatConfig.mode), // 根據mode來區呼叫介面 concatConfig.config // 使用者傳的引數 ) let returnData = { } if(qrcodeInfo.type.indexOf('image') !== -1) { //型別是圖片的就是獲取成功了 // 請求成功 儲存圖片 returnData = { code: 200, image: qrcodeInfo.data, error: null } } else { returnData = { code: 500, error: JSON.stringify(qrcodeInfo.data.toString()), image: null } } return returnData } 複製程式碼
寫好後讓我們測試一下
let qrocode = new miniQrcode({ appId: 'xxx', appSecret: 'xxx' }); let info = await qrocode.getWxQrcodeInfo({ mode: 'getWXACode', config: { path: `pages/index/main?id=123456` }, }) fs.writeFileSync(`./output-juejin-test1.png`, info.image, 'utf8'); 複製程式碼
效果:

如何測試引數?我在這個已經發布的小程式裡面加了個彩蛋,就是長按 紅色圈出區域兩次
即可調出控制檯看引數

將二維碼合成到模板圖片裡面
這個操作依賴於 sharp
庫
const sharp = require('sharp'); class miniSharp { constructor(templateUrl){ this.templateUrl = templateUrl } // 重置圖片大小 async resizeQrcode(imageBuffer, config){ return new Promise(resolve => { sharp(imageBuffer).resize(config.width, config.width).toBuffer().then(function(outputBuffer) { resolve(outputBuffer) }); }) } // 合併圖片 async concatImage(buffer, config){ return new Promise(resolve => { sharp(this.templateUrl) .overlayWith(buffer, { top: config.top, left: config.left }).toBuffer().then(function(outputBuffer) { resolve(outputBuffer) }); }) } // 主函式 async renderImage(qrcodeBuffer, config){ let resizeQrcodeBuffer = await this.resizeQrcode(qrcodeBuffer, config) let concatQrocdeBuffer = await this.concatImage(resizeQrcodeBuffer, config) return concatQrocdeBuffer } } module.exports = miniSharp 複製程式碼
測試一下
let qrocode = new miniQrcode({ appId: 'xxxx', appSecret: 'xxx' }); let mySharp = new miniSharp('./template.png'); let info = await qrocode.getWxQrcodeInfo({ mode: 'getWXACode', config: { path: `pages/index/main?id=123456` }, }) let renderBuffer = await mySharp.renderImage(info.image, // 二維碼圖片的 buffer 陣列 { width: 200, // 重新設定二維碼寬度 left: 362, // x軸偏移 top: 53 // y軸偏移 }) fs.writeFileSync(`./output-juejin-test1.png`, renderBuffer, 'utf8'); 複製程式碼


批量處理
正常情況下,批量生成 100
張需要 62.556秒
,平均每張需要 0.62556秒
,1萬張大概需要 1.73小時
。 批量示例程式碼
關於除錯
使用微信開發者工具可以進行模擬引數除錯

測試介面
這裡我提供了一個測試介面,可以帶引數生成線上的小程式碼,用來除錯
[get]
http://wx.toolos.cc
引數
-
mode
必傳 [createWXAQRCode | getWXACode | getWXACodeUnlimit] 之一
注意
- 其他引數對應上面的文件的
mode
對應的引數,path
或者page
需要encodeURIComponent
一下 - 目前小程式只有一個路徑
pages/index/main
- 線上伺服器配置低
示例
http://wx.toolos.cc/?mode=createWXAQRCode&path=pages%2Findex%2Fmain 複製程式碼
關於引數模式
createWXAQRCode & getWXACode
這兩種生成的引數,生成二維碼數量有限,引數直接跟在path路徑後面,例如:
let info = await qrocode.getWxQrcodeInfo({ mode: 'createWXAQRCode', config: { page: `pages/index/main?sgr=521314&i=loveyou` }, }) 複製程式碼

getWXACodeUnlimit
這個可以生成無限個,但是隻能攜帶有侷限性的引數 scene
,在這裡推薦一種解析方式 key:value-key:value
let info = await qrocode.getWxQrcodeInfo({ mode: 'getWXACodeUnlimit', config: { page: `pages/index/main`, scene: 'i:loveyou-sgr:521314' }, }) 複製程式碼

解析示例
onLoad (query) { // scene 需要使用 decodeURIComponent 才能獲取到生成二維碼時傳入的 scene this.scene = decodeURIComponent(query.scene) this.queryJson = JSON.stringify(query) // 嘗試解析scene 格式: shop:1-id:2 try { let oneArr = this.scene.split('-') let twoJson = {} for(let i=0; i<oneArr.length; i++) { let target = oneArr[i].split(':') twoJson[target[0]] = target[1] } this.twoJson = JSON.stringify(twoJson) } catch(e) { this.twoJson = e } }, 複製程式碼
在開發者工具中例如下面模擬
