Node调用小程序服务端接口生成小程序二维码

363 阅读2分钟

背景

前段时间公司内部有一个安卓小项目,安卓内部调用前端的H5做展示,我负责H5这一块的开发
产品提了一个需求,在项目里面增加展示公司的一个微分销小程序的小程序码,这里简单记录一下自己的做这个功能的经历和踩的坑

技术架构

负责的H5项目采用的前后端分离的架构
前端页面部分用的 vue2
应用层采用 nodejs (koa2) ,通过nodejs去调用后端的SOA服务来封装应用层的接口

思路

1.小程序文档中提供了对应的方法去动态生成一张小程序码的图片,所需参数可以详见小程序的官方文档;
2.和小程序开发的同事确定好生成小程序码所需要的参数,针对我这个项目就是'pages/index/index?sellerId=xxx',sellerId参数处理这里不做介绍,根据实际项目而异;
3.小程序接口返回一个buffer,调用Nodejs的fs.writeFileSync方法将这个buffer转换成一张图片并保存在指定路径,返回这个路径
4.前端页面中得到这个路径后去请求这张图片,这时候需要node端做好对应的路径处理,我这里用的是koa-static,当请求指定路径的时候能指向对应的资源(生成的图片);
5.前端获取到图片资源后再发一个请求删除这张图片,因为小程序码是有有效时间的,所以每次都得重新生成,临时文件已经没有作用了

nodejs(koa2)生成图片方法

exports.getWechatSalesQrcode = async function (ctx, next) {
  try {
    let bodyParams = ctx.request.body;
    let miniProgramConfig = Object.assign({}, constants.MINI_PROGRAM_CONFIG[bodyParams.brandCode]);
    miniProgramConfig.path = 'pages/index/index?sellerId=35226134';   // todo 先写死sellerId
    if (!miniProgramConfig) {
      ctx.body = {
        success: false
      }
    }
    let qrcodePhotoNameUrl = await generateMiniProgramQrcodeImg(miniProgramConfig, 'weidian');
    ctx.body = {
      url: qrcodePhotoNameUrl
    };
  } catch (e) {
    ctx.body = {
      success: false
    }
  }
};

/**
 * 生产小程序二维码图片url
 * @param miniProgramConfig 小程序配置
 * @param fileName 二维码图片名
 * @param fileType  图片类型
 * @returns {Promise<string>}
 */
async function generateMiniProgramQrcodeImg(miniProgramConfig, fileName = 'qrcode', fileType = 'png') {
  let imgBuffer = await getMiniProgramQrcodePromise(miniProgramConfig);
  let time = new Date().getTime();
  let qrcodePhotoName = fileName + time + '.' + fileType;
  fs.writeFileSync('./public/pic/' + qrcodePhotoName, imgBuffer);
  return '/api/media/pic/' + qrcodePhotoName;
}

/***
 * 调用小程序服务端接口生成对应小程序二维码
 * @param param 包含小程序的appid和secret 入口path 图片宽度width
 * @returns {Promise<any>}
 */
function getMiniProgramQrcodePromise(param) {
  return new Promise(resolve => {
    let url = `https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=${param.appid}&secret=${param.secret}`
    request(url, {}, function (error, response, body) {
      if (response.statusCode === 200 && body) {
        let access_token = JSON.parse(body).access_token;
        let qrcodeUrl = `https://api.weixin.qq.com/cgi-bin/wxaapp/createwxaqrcode?access_token=${access_token}`;
        request.post({
          url: qrcodeUrl,
          body: {
            scene: 1049,
            path: param.path,
            width: param.width || 280
          },
          encoding: null,       // request默认会进行编码,设置为null使其不要编码原因返回
          json: true,
        }, function (error, response, body) {
          let imgBuffer = Buffer.from(body, 'binary');
          resolve(imgBuffer);
        });
      } else {
        resolve(false);
      }
    });
  })
}

常量配置

// 微分销小程序配置
exports.MINI_PROGRAM_CONFIG = {
  '6': {
    appid:  "xxx",
    secret:   "xxxx"
  }
};

koa2提供静态资源访问

var koa = require('koa');
var app = new koa();
var serve = require('koa-static-server')
app.use(serve({ rootDir: './public/pic', rootPath: '/api/media/pic' }));
app.use(serve({ rootDir: './public/pdf', rootPath: '/api/media/pdf' }));

前端代码 vue2

<template>
  <section class="get-coupon-area">
    <div class="inside-coupon-content">
      <div class="get-coupon-content">
        <div class="qrcode-img">
          <img v-show="qrCodeUrl" :src="qrCodeUrl" @load="loadImgSuccess">
        </div>
      </div>
    </div>
  </section>
</template>
export default {
    name: 'get-coupon',
    data() {
        return {
            qrCodeUrl: '',
            couponPasscode: '',
            qrCodeFileName: ''
        }
    },
    mounted() {
        getWechatSalesQrcode({brandCode: this.brandCode, clerkNo: this.clerkNo}).then(res => {
            if (res && res.url) {
              this.qrCodeUrl = '/api/media/pic/' +  res.url;
              this.qrCodeFileName = res.url;
              let img = new Image();
              img.src = this.qrCodeUrl;
              img.onload = function () {
                unlinkImg({fileName: res.url}).then(res => {
                  console.log('图片删除成功!')
                });
              };
              // console.log(this.qrCodeUrl);
            }
      });
    }

}

nginx修改

开发这个功能的时候在我本地调试是没有问题的,但是到了生产的时候发现获取图片的时候404,排查了代码没有发现问题。。
后来想到了是否是nginx配置的问题,之前为了节省带宽和缓解服务器的压力,跟运维约定好一些静态资源到制定的目录获取,而且设置缓存时间
针对我这个需求的话因为小程序码是动态生成的,不能缓存,而且不在约定好的那个位置,所以这个配置的影响了获取图片

原先的配置

location ~ .*\.(html|htm|gif|jpg|jpeg|bmp|png|ico|txt|js|css)$
    {
        root /data/static/xxxx/dist;
        ## expires定义用户浏览器缓存的时间为7天,如果静态页面不常更新,可以设置更长,这样可以节省带宽和缓解服务器的压力
        expires      7d;
    }

修改方案

因为生成的图片是png格式的,其他静态资源没有png格式的,所以和运维商量了一下nginx配置中去掉了png格式,这样就可以正常获取

参考链接:blog.csdn.net/uikoo9/arti…