问题来源

  1. 最近在做某项目的技术调研,其中后端是用koa+mongodb实现的(其实就是nodejs搭建的一套后台服务),有个需求是希望生成微信小程序码(也称葵花码)。<br />微信官方相关资料:

生成小程序码各种问题

因涉及到的为公司内部项目,故会对appid/secret等关键信息用xxxxxx进行代替,实际copy的时候替换成真实的小程序信息即可。

node生成小程序码有俩个关键步骤:

  • 获取小程序接口调用凭证access_token
  • 获取小程序码

下面我们用代码实际跑一下看怎么生成?

  • 新建server.js ``` const config = { appid: ‘xxxxxx’, secret: ‘xxxxxx’ } const https = require(‘https’);

// 1-获取到access_token https.get(https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=${config.appid}&secret=${config.secret}, (response) => { let todo = ‘’; response.on(‘data’, (chunk) => { todo += chunk; }); response.on(‘end’, () => { const { access_token, expires_in } = JSON.parse(todo) if (access_token && expires_in) { // 2-获取太阳码接口 getQRCode(access_token)

  1. }

}); }).on(“error”, (error) => { console.log(“Error: “ + error.message); });

function getQRCode(access_token) { const data = JSON.stringify({ access_token }) const options = { hostname: ‘api.weixin.qq.com’, path: ‘/wxa/getwxacodeunlimit’, method: ‘POST’, headers: { ‘Content-Type’: ‘application/json’, ‘Content-Length’: data.length } }

console.log(‘请求参数数据’, data) const req = https.request(options, res => { res.on(‘data’, d => { console.log(‘d:’, d.toString()) }) }) req.write(data) req.on(‘error’, error => { console.error(error) }) req.end() }

  1. - 执行node server.js启动node服务后,我们查看运行效果: <br />Error: {"errcode":41001,"errmsg":"access_token missing rid: 62bbbb20-4d960a62-65f840a8"}<br />![image.png](https://cdn.nlark.com/yuque/0/2022/png/1607809/1656514523787-d2e0a6d6-477b-4e1a-a634-e182a6ceffe4.png#clientId=u87fb75e6-293d-4&crop=0&crop=0&crop=1&crop=1&from=paste&height=82&id=u4e6f83b5&margin=%5Bobject%20Object%5D&name=image.png&originHeight=204&originWidth=1498&originalType=binary&ratio=1&rotation=0&showTitle=false&size=33520&status=done&style=none&taskId=ub1019e70-0026-474d-b7cc-8db0cf149ef&title=&width=599.2)
  2. > 报错原因分析: 微信很多接口是以post方式请求的,参数一般也是以json格式传入的, But这个access_token需要以get的方式拼接在url上进行传递,否则微信接口收不到。
  3. 我们看下微信官方截图:<br />![image.png](https://cdn.nlark.com/yuque/0/2022/png/1607809/1656514871055-d117388c-0ae8-4192-ac59-b3b8ce79ec34.png#clientId=u87fb75e6-293d-4&crop=0&crop=0&crop=1&crop=1&from=paste&height=374&id=u17d9b3b6&margin=%5Bobject%20Object%5D&name=image.png&originHeight=936&originWidth=1894&originalType=binary&ratio=1&rotation=0&showTitle=false&size=160559&status=done&style=none&taskId=u2812ad65-d58a-4e73-ac5b-1992103277e&title=&width=757.6)
  4. - 我们修改代码如下:

// 将access_token附加在请求url上. path: /wxa/getwxacodeunlimit?access_token=${access_token},

  1. - 再次执行node server.js启动node服务后,我们查看运行效果: <br />Error: {"errcode":47001,"errmsg":"data format error rid: 62bbbe2a-4decf6d0-6cb9333a"}<br />![image.png](https://cdn.nlark.com/yuque/0/2022/png/1607809/1656514676627-31f309af-5966-4fe7-82de-0c10ab39870b.png#clientId=u87fb75e6-293d-4&crop=0&crop=0&crop=1&crop=1&from=paste&height=82&id=u7b6812a4&margin=%5Bobject%20Object%5D&name=image.png&originHeight=204&originWidth=1488&originalType=binary&ratio=1&rotation=0&showTitle=false&size=32642&status=done&style=none&taskId=u83cd4a62-6adf-41cd-97ed-01634d641ca&title=&width=595.2)
  2. > 报错原因分析: 格式化json数据有误,原来是有一些必传参数未传递。
  3. - 我们修改代码如下:

const data = JSON.stringify({ scene: ‘id=2’, // scene参数根据实际需要填写即可 page: ‘pages/index/index’ })

  1. - 再次执行node server.js启动node服务后,我们查看运行效果: <br />Error: {"errcode":41030,"errmsg":"invalid page rid: 62bbbff3-5b8aeb3c-3fd4b88a"}<br />![image.png](https://cdn.nlark.com/yuque/0/2022/png/1607809/1656514914595-5ad95916-51c2-435c-b918-4f024fc84ddc.png#clientId=u87fb75e6-293d-4&crop=0&crop=0&crop=1&crop=1&from=paste&height=85&id=u49b3c531&margin=%5Bobject%20Object%5D&name=image.png&originHeight=213&originWidth=1488&originalType=binary&ratio=1&rotation=0&showTitle=false&size=26701&status=done&style=none&taskId=u42f0efda-2734-4d40-b535-b87916a5bd1&title=&width=595.2)
  2. > 报错原因分析:page不合法,可能原因是页面不存在或者小程序未发布。在这里例子中是由于小程序未发布到线上,故该页面找不到,所以报错了。
  3. - 我们修改代码如下:

const data = JSON.stringify({ scene: ‘id=2’, // scene参数根据实际需要填写即可 page: ‘pages/index/index’, // 入参新增check_path字段 check_path: false })

  1. 至此,你以为大概率可以正常生成小程序码了,答案当然是错误的,请接着往下看。
  2. <a name="AMDYT"></a>
  3. ## arraybuffer转图片
  4. > 上面的代码片段只解决了接口层调用的问题,但未解决如何接收post请求返回体。
  5. - 修改代码如下:

res.on(‘end’, () => { console.log(‘post请求接收到的参数:’, body) // 将二进制流图片转换生成真实的图片 fs.writeFile(‘test.png’, body, function (err) { if (!err) { console.log(‘图片生成成功=.=’) } }) })

  1. - 我们重启看下node服务,我们会发现接收到的数据乱码了
  2. ![image.png](https://cdn.nlark.com/yuque/0/2022/png/1607809/1656592542855-1a7a7b42-f862-4e68-be44-3e6802fbb383.png#clientId=u6e7bbd26-c3e0-4&crop=0&crop=0&crop=1&crop=1&from=paste&height=366&id=u750e82a8&margin=%5Bobject%20Object%5D&name=image.png&originHeight=915&originWidth=1568&originalType=binary&ratio=1&rotation=0&showTitle=false&size=148925&status=done&style=none&taskId=uac692825-c092-43ea-874e-d1472015f87&title=&width=627.2)<br />But图片生成成功了,我们看下能否打开,oh no,是不行的,说明格式不对。<br />![image.png](https://cdn.nlark.com/yuque/0/2022/png/1607809/1656592557654-c4208326-5ffa-4e65-a831-50e81bfd06a6.png#clientId=u6e7bbd26-c3e0-4&crop=0&crop=0&crop=1&crop=1&from=paste&height=315&id=ub811fca2&margin=%5Bobject%20Object%5D&name=image.png&originHeight=787&originWidth=1564&originalType=binary&ratio=1&rotation=0&showTitle=false&size=102143&status=done&style=none&taskId=u2357c2e5-6a45-4469-a71b-0c1785f0c02&title=&width=625.6)
  3. <a name="Zsbcu"></a>
  4. ## 生成小程序码code
  5. > 下面的代码,修改下appid&secret即可正常运行。

// 最终代码如下: const config = { appid: ‘xxxxxx’, secret: ‘xxxxxx’ } const https = require(‘https’);

// 1-获取到access_token https.get(https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=${config.appid}&secret=${config.secret}, (response) => { let todo = ‘’; response.on(‘data’, (chunk) => { todo += chunk; }); response.on(‘end’, () => { const { access_token, expires_in } = JSON.parse(todo) if (access_token && expires_in) { // 2-获取太阳码接口 getQRCode(access_token)

  1. }
  2. });

}).on(“error”, (error) => { console.log(“Error: “ + error.message); });

function getQRCode(access_token) { const axios = require(‘axios’) const fs = require(‘fs’)

  1. const data = {
  2. scene: 'id=2',
  3. page: 'pages/index/index'
  4. }
  5. axios({
  6. url: `https://api.weixin.qq.com/wxa/getwxacodeunlimit?access_token=${access_token}`,
  7. method: 'POST',
  8. // 很关键
  9. responseType: 'arraybuffer',
  10. data: data,
  11. }).then(body => {
  12. let {
  13. data
  14. } = body
  15. const buffer = data
  16. console.log(buffer, 'buffer')
  17. // 将二进制流图片转换生成真实的图片
  18. fs.writeFile('test.png', buffer, function (err) {
  19. if (!err) {
  20. console.log('图片生成成功=.=')
  21. }
  22. })
  23. })

} ```

  • 重启node服务,我们能发现是能正常生成图片的(涉及到公司内部项目,不方便贴图,自己跑下代码就行)

    写在最后

    nodejs request模块怎么设置responseType呢? 因为暂未找到解决方案, 暂时先切换成用axios模块吧.