如果不需要后端java或者其他语言支持,对于小型的小程序后台,可以使用eggjs框架快速搭建简要的数据后台。

如果未接触过node编写接口,首先还是需要基本过一下egg官方文档,至少得把快速入门看完。

不会从头开始把每一步都详细写下来,只针对微信对接的一些处理列出来。

数据库

使用mongo,示例通过egg-mongoose进行连接处理。

安装插件后,在/config/plugin.js进行基本配置:

mongoose: {
  enable: true,
  package: 'egg-mongoose'
}

/config/config.default.js文件中配置mongodb的连接(保证本地测试环境数据库连接好):

// connect mongo
  config.mongoose = {
    client: {
      url: 'mongodb://127.0.0.1/fulishe',
      options: {},
    }
  }

/app/models文件夹编写相关的model,在程序运行时会自动在mongo上创建对应的表。也可以优先创建好数据库和表设计等。

编写接口

controller写主要的业务逻辑,接受接口请求参数并返回。 对于入参,需要进行验证的可以做验证处理,需要处理返回结果,即使请求出错也不要返回非200的状态码。 可以将处理结果设置为一个函数,如:

// data: 返回给前端的数据,code: 状态,1为成功,0为失败,message:状态信息
formatResponse: function (data, code, message) {
  return {
    code,
    data,
    message
  }
}

!> 为避免出现出现问题而导致程序中断,最好在每一个容易出现问题的地方进行try catch将异常抛出并返回到前端。

service编写数据库操作函数等,通过在controller进行调用,统一管理数据库数据进出。 注意在数据新增的时候需要进行save操作:

const addUser = await this.ctx.model.Users(data)
addUser.save() // 不要遗漏

相关的增删改查操作,需要直接点的可以看仓库app/service下的写法。

小程序接口相关

以下是eggjs对小程序包括获取openId、获取unionId、获取手机号码、判断用户是否关注公众号、客服信息发送进行编写说明。
如果某个对象不知道是什么,一般都是可以根据名字找到对于的js文件或者通过npm引入,不再表述引入什么了。

获取openId

参数说明:

  • APPID: 小程序的appId
  • SECRET: 小程序的secret,跟appId在同一个地方能找到
  • CODE:小程序在前端通过wx.login()获取的jscode
const openIdRes = await rp(`https://api.weixin.qq.com/sns/jscode2session?appid=${APPID}&secret=${SECRET}&js_code=${CODE}&grant_type=authorization_code`)
const openId = JSON.parse(openIdRes).openId // 在处理错误判断后,返回的数据是json字符串,需要转化

获取unionId

unionId,属于微信端通用的账号唯一标识,举个例子就是同一个微信号,唯一对应一个unionId。而在每一个小程序上,用户openId都不一样。可以用于判断在小程序上的用户是否关注公众号等。

在第一个获取openId的时候,会返回openId以及session_key,通过小程序前端传过来的encryptedData以及iv就可以拿到unionId

参数说明:

  • APPID: 小程序的appId
  • sessionKey:获取openId的时候,一并返回了sessionKey
  • encryptedData:小程序在前端通过获取用户信息返回
  • iv:小程序在前端通过获取用户信息返回
const pc = new WXBizDataCrypt(APPID, sessionKey)
const data = pc.decryptData(encryptedData, iv)
const unionId = data.unionId

获取手机号码

获取手机号码的步骤跟获取unionId一样。

只需要注意的是,encryptedDataiv是在小程序端通过getPhoneNumber获取。

判断用户是否关注公众号

这里单独在小程序后台无法判断。需要在对于的公众号后台提供一个接口用于判断该unionId是否已经关注了公众号。

客服信息发送

在小程序开发设置中配置消息推送。

配置参考:

参数 备注
URL(服务器地址) https://..com/message/check 微信那边与你服务器通信的接口
Token(令牌) isToken 自定义
EncodingAESKey(消息加密密钥) ** 填写那可以自动生成
消息加密方式 兼容模式 涉及信息安全
数据格式 JSON 一般是这个吧

controller层编写一个get接口,对应/message/check,用以给微信进行服务器验证。 完整验证函数接口可如下:

async index() {
  const { ctx } = this
  // 1.获取微信服务器Get请求的参数 signature、timestamp、nonce、echostr
  const {
    signature,
    timestamp,
    nonce,
    echostr
  } = ctx.query

  // 2.将token、timestamp、nonce三个参数进行字典序排序
  let array = ['线上配置的令牌', timestamp, nonce]
  array.sort() // JavaScript sort函数就是字典序排序的

  // 3.将三个参数字符串拼接成一个字符串进行sha1加密
  const tempStr = array.join('')
  const hashCode = crypto.createHash('sha1') //创建加密类型
  const resultCode = hashCode.update(tempStr, 'utf8').digest('hex')

  // 4.开发者获得加密后的字符串可与signature对比,标识该请求来源于微信
  if (resultCode === signature) {
    ctx.body = echostr
  } else {
    // 非微信服务器请求
    ctx.body = format.formatResponse({
      resultCode,
      req: ctx.query
    }, 0, '验证失败1')
  }
}

自动回复操作: 在controller层编写一个post接口,对应/message/check,用于自动回复。 完整处理自动回复接口:

async handle() {
  const { ctx } = this
  const { FromUserName, MsgType, Content } = ctx.request.body // 这是从微信转发过来的用户发送的信息参数
  const { openid } = ctx.query
  // 获取accessToken
  const tokenRes = await rp(`https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=${CONST.appId}&secret=${CONST.secret}`)
  if (!('errcode' in JSON.parse(tokenRes))) {
    if (MsgType === 'text') {
      const postData = {
        touser: openid,
        msgtype: "link",
        link: {
          title: '链接标题',
          description: '链接描述',
          url: '链接',
          thumb_url: '链接封面图'
        }
      }
      const sendRes = await rp({
        uri: `https://api.weixin.qq.com/cgi-bin/message/custom/send?access_token=${JSON.parse(tokenRes).access_token}`,
        method: 'post',
        body: postData,
        json: true
      })
    }
  }
  ctx.body = 'success'
}

!> 注意:需要在自动回复的最后返回success,否则会在聊天窗口看到提示:该小程序提供的服务出现故障,请稍后再试