Koa development of micro-channel public number

Micro-channel developer mode on required server domain name is legitimate and the configured interface, which is the key on, after turning on the micro letter backstage menu setup functions, customer service functions will fail, require developers to customize menus and intelligent customer service interface, and after the call can be turned inside the micro-channel location sharing pages functions

Prerequisites

  • First look koa and mongoose essay notes
  • Middleware installation xml2js
  • [Flyio middleware installation request or axios also OK]
  • Create a separate folder wx

A method of packaging borrow xml2js

// utils/xml.js

const xml2js = require('xml2js')

exports.xmlToJson = (str) => {
     return new Promise((resolve, reject) => {
        const parseString = xml2js.parseString
        parseString(str, (err, result) => {
            if (err) {
                reject(err)
            } else {
                resolve(result)
            }
        })
     })
}

exports.jsonToXml = (obj) => {
    const builder = new xml2js.Builder()
    return builder.buildObject(obj)
}

A custom xml middleware
if the data is first processed into a format xml format json

// middleware/xmlParse.js

const xml = require('../util/xml')

module.exports = () => {
    return async (ctx, next) => {
        if (ctx.method == 'POST' && ctx.is('text/xml')) {
            let promise = new Promise(function (resolve, reject) {
                let buf = ''
                ctx.req.setEncoding('utf8')
                ctx.req.on('data', (chunk) => {
                    buf += chunk
                })
                ctx.req.on('end', () => {
                    xml.xmlToJson(buf)
                        .then(resolve)
                        .catch(reject)
                })
            })
            await promise.then((result) => {
                    ctx.req.body = result
                })
                .catch((e) => {
                    e.status = 400
                })
            await next()
        } else {
            await next()
        }
    }
}

Profiles

// config.js
...
wx: {
  // 这几个都是微信给的
  appid: 'AppSecret',
  AppSecret:'AppSecret',
  token:'token',
  encodingAESKey: 'encodingAESKey',
},
...

Micro message routing

// router/index.js

const wxSignature = require('../wx/wxSignature')
const wxHandle = require('../wx/wxHandle')

router.get('/wxHandle', wxHandle.getHandle)
router.post('/wxHandle', wxHandle.postHandle)

sha1 encryption

// utils/encode.js

const crypto = require('crypto')

exports.sha1 = (str) => {
    const sha1 = crypto.createHash('sha1')
    sha1.update(str)
    return sha1.digest('hex')
}

Core micro-channel constructor
the closure several values in the constructor, the expiration time is, until the token expires before requesting again

// wx/index.js

const config = require('../config')
const request = require('request');

function wxchat(config) {
    this.appid =  config.appid;
    this.AppSecret =  config.AppSecret;
    this.token =  config.token;
    this.encodingAESKey =  config.encodingAESKey;
    this.accessToken =  "";
    this.accessTokenTime =  "";
    this.jsapiTicket =  "";
    this.jsapiTicketTime =  "";
}
wxchat.prototype.getAccessToken = async function(){
    if(this.accessToken==""){
        await this.accessTokenRequest();
    }else{
        var now = new Date().getTime()
        if(now>Number(this.accessTokenTime)){
            // 过期了
            await this.accessTokenRequest();
        }
    }
    return this.accessToken
}

wxchat.prototype.accessTokenRequest = async function(){
    var url = 'https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential';
    url += '&appid=' + this.appid;
    url += '&secret=' + this.AppSecret;
    return new Promise((resolve,reject) => {
        request(url,(error, response, body) => {
            if(response.statusCode == 200){
                var res = JSON.parse(body);
                if(res.access_token){
                    console.log("accessToken成功:"+ res.access_token)
                    this.accessToken = res.access_token;
                    this.accessTokenTime = new Date().getTime() + Number(res.expires_in) - 200;
                }else{
                    console.log("获取accessToken接口出错:"+res.errcode)
                    this.accessToken = "";
                    this.accessTokenTime = "";
                }
            }else{
                console.log("获取accessToken接口出错")
                this.accessToken = "";
                this.accessTokenTime = "";
            }
            resolve()
        })
    })
}

wxchat.prototype.init=async function () {
   await this.getAccessToken()
}

const wx = new wxchat(config.wx);
wx.init()

module.exports = wx;

Entry file

// app.js
 
const xmlParse = require('./src/middleware/xmlParse')
// 这个js是自启动服务,不需要use,每次启动都会自动获取access_token
const wx = require('./src/wx/index')

app.use(xmlParse());

Switched services and intelligent call
all of the code above is to serve this js

// wx/wxHandle.js

const encode = require('../util/encode')
const config = require('../config')
const xml = require('../util/xml')

//公众号接通服务
exports.getHandle = async (ctx, next) => {
    const token = config.wx.token,
        signature = ctx.query.signature,
        timestamp = ctx.query.timestamp,
        nonce = ctx.query.nonce;
    // 字典排序
    const arr = [token, timestamp, nonce].sort()
    const result = encode.sha1(arr.join(''))

    if (result === signature) {
        ctx.body = ctx.query.echostr
    } else {
        ctx.body = { code: -1, msg: "你不是微信!"}
    }
}

//微信客服,回复
exports.postHandle = (ctx, next) => {
    let msg,MsgType,result;
    msg = ctx.req.body ? ctx.req.body.xml : ''

    if (!msg) {
        ctx.body = 'error request.'
        return;
    }
    MsgType = msg.MsgType[0]
    if(MsgType=='text'){
        // 文字回复
        result = xml.jsonToXml({
                xml: {
                    ToUserName: msg.FromUserName,
                    FromUserName: msg.ToUserName,
                    CreateTime: Date.now(),
                    MsgType: msg.MsgType,
                    Content: msg.Content
                }
        })
    }else if(MsgType=='event'){
        // 关注回复
        result = xml.jsonToXml({
            xml: {
                ToUserName: msg.FromUserName,
                FromUserName: msg.ToUserName,
                CreateTime: Date.now(),
                MsgType: 'text',
                Content: "感谢关注"
            }
        })
    }else{
        // 其他回复
        result = 'success'
    }
    ctx.res.setHeader('Content-Type', 'application/xml')
    ctx.res.end(result)
}

After the above code is set up, go outside the domain name to start the service, if the service starts successfully, go back to the micro-channel server Touch ON, will need to fill turned request address, domain name server is [/ xxx / wxHandle], After clicking Finish , micro letter will be issued to address this request is a xml request, the request reaches Koa server we have just opened, the middleware is parsed into Json, and then after calculation by config.js in encryption appId return data to the micro-channel, no problems is switched on, and after turning on the success go to public concern number, you can receive just configured welcome [attention], you then send the text up, he will send you back to re-send, end Sahua

Smart customer service can not be used to write the code, you need to be a page to configure the database, the database server to check the user's reply to the request, there is also the configuration menu, the configuration menu is the need for certified public number, 300 per year, I did not do there is also a micro-letter web page signature interface enables get the address, sharing, micro-letter web page in the Share and access to address how to write, there are at Js notes, how this interface to write, view github, helpful to the stars Thank you!

Micro-channel user login access to information, view the next one

Guess you like

Origin www.cnblogs.com/pengdt/p/12072512.html