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

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

引言

未標題-2.png

最近有一個生成很多小程式碼的需求,生成的小程式碼還要嵌入在指定的圖片模板上,就去找輪子,沒找到合適的輪子。。無奈之下就決定去擼一個。目前已經完成併發布npm。

Github: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');
複製程式碼

效果:

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

Screenshot_2018-11-17-10-55-13-286_com.tencent.mm.png

將二維碼合成到模板圖片裡面

這個操作依賴於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');
複製程式碼

template.png

批量處理

正常情況下,批量生成100張需要62.556秒,平均每張需要0.62556秒,1萬張大概需要 1.73小時批量示例程式碼

關於除錯

使用微信開發者工具可以進行模擬引數除錯

QQ截圖20181117104623.png

測試介面

這裡我提供了一個測試介面,可以帶引數生成線上的小程式碼,用來除錯

[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`
  },
})
複製程式碼

output-createWXAQRCode.png

getWXACodeUnlimit

這個可以生成無限個,但是隻能攜帶有侷限性的引數scene,在這裡推薦一種解析方式 key:value-key:value

let info = await qrocode.getWxQrcodeInfo({
  mode: 'getWXACodeUnlimit',
  config: {
    page: `pages/index/main`,
    scene: 'i:loveyou-sgr:521314'
  },
})
複製程式碼

output-getWXACodeUnlimit.png

解析示例

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
  }

},
複製程式碼

在開發者工具中例如下面模擬

QQ截圖20181117104623.png