nodejs微信公众号开发——2.自动回复

in 编程
关注公众号【好便宜】( ID:haopianyi222 ),领红包啦~
阿里云,国内最大的云服务商,注册就送数千元优惠券:https://t.cn/AiQe5A0g
腾讯云,良心云,价格优惠: https://t.cn/AieHwwKl
搬瓦工,CN2 GIA 优质线路,搭梯子、海外建站推荐: https://t.cn/AieHwfX9
上一篇文章:nodejs微信公众号开发(1)接入微信公众号,本篇文章将在此基础上实现简单的回复功能。(项目github地:https://github.com/Panfen/wem... )

1. 接入代码的优化

之前我们简单粗暴的实现了微信公众号的接入,接入的代码直接写在了app.js文件里面,从项目开发的角度而言,不便于日后代码的维护,所以将这部分代码独立出来,按照koa的风格,写成一个中间件。
在根目录下新建wechat文件夹,新建generator.js文件,

var sha1 = require('sha1');

module.exports = function(opts){
    return function *(next){
        var token = opts.token;
        var signature = this.query.signature;
        var nonce = this.query.nonce;
        var timestamp = this.query.timestamp;
        var echostr = this.query.echostr;
        var str = [token,timestamp,nonce].sort().join('');
        var sha = sha1(str);
        this.body = (sha === signature) ? echostr + '' : 'failed';
    };
}

此时app.js的内容变成:

'use strict'

var Koa = require('koa');
var generator= require('./wechat/generator');

var config = {
    wechat:{
        appID:'...',
        appSecret:'...',
        token:'...'
    }
};

var app = new Koa();
app.use(generator(config.wechat));
app.listen(8080);

console.log('Listening 8080...')

2. 获取access_token

access_token是开发程序与wexin公众平台交互的一把钥匙,调用绝大部分接口都需要用到access_token
access_token的特点:

解决方案:

程序中采用构造函数的方式,在生成实例,完成初始化工作的的过程中,读取存储在config/wechat.txt文件中的票据,判断是否为空且是否过期,选择性的重新获取数字并且保存在原文件里面,关于获取access_token的官方文档介绍可见:获取access_token

function Wechat(opts){     //构造函数,用以生成实例,完成初始化工作,读写票据
    var that = this;
    this.appID = opts.appID;
    this.appSecret = opts.appSecret;
    this.getAccessToken = opts.getAccessToken;
    this.saveAccessToken = opts.saveAccessToken;

    this.getAccessToken().then(function(data){
        try{
            data = JSON.parse(data);
        }catch(e){
            return that.updateAccessToken();
        }
        if(that.isvalidAccessToken(data)){
            Promise.resolve(data);
        }else{
            return that.updateAccessToken();
        }
    }).then(function(data){
        that.access_token = data.access_token;
        that.expires_in = data.expires_in;
        that.saveAccessToken(JSON.stringify(data));
    });
}

我们在moudle.exports中实例化一个Wechat

var wechat = new Wechat(opts);

这样确保了每次程序启动都会获取对access_token的有效性进行检验,并且每个一段时间会自动获取一个新的access_token

3. 处理微信消息的步骤

无论是事件推送还是消息推送,微信服务器都是以post的方式发送请求,推送的数据类型不是json而是xml,处理推送消息一般分为五个步骤:

3.1 接收xml数据

通过raw-body模块可以获取http模块中的request对象,并且可以对数据进行拼装,从而拿到一个buffer的xml对象

var data = yield rawBody(this.req,{
               length:this.length,
               limit:'1mb',
               encoding:this.charset
           });
console.log('data:'+data);

图片描述

3.2 解析xml数据

使用xml2js模块,将xml数据解析成对象格式

var content = yield util.parseXMLAsync(data);  

util中的parseXMLAsync方法:

exports.parseXMLAsync = function(xml){
    return new Promise(function(resolve,reject){
        xml2js.parseString(xml,{trim:true},function(err,content){
            err ? reject(err) : resolve(content);
        })
    });
}

图片描述

3.3 格式化xml数据

从解析的xml数据来看,数据虽然已经呈现键值对的形式,但是其值是数组的形式,需要进行扁平化处理:

var message = util.formatMessage(content.xml);

其本质就是遍历数组中的值,因为在多图文的消息中存在嵌套的情况:

function formatMessage(result){
    var message = {};
    if(typeof result === 'object'){
        var keys = Object.keys(result);
        for(var i=0;i<keys.length;i++){
            var key = keys[i];
            var item = result[key];
            if(!(item instanceof Array) || item.length === 0) continue;
            if (item.length === 1){
                var val = item[0];
                if (typeof val === 'object') message[key] = formatMessage(val);
                else message[key] = (val || '').trim();
            }else{
                message[key] = [];
                for(var j=0,k=item.length;j<k;j++) message[key].push(formatMessage(item[j]));
            }
        }
    }
    return message;
}

图片描述

3.4 判断消息类型并回复

这里针对subscribe事件,新关注后自动回复文本消息终于等到你,还好我没放弃

if(message.MsgType === 'event'){
    if(message.Event === 'subscribe'){
        var createTime = new Date().getTime();
        that.status = 200;
        that.type = 'application/xml';
        that.body = '<xml>'+
                    '<ToUserName><![CDATA['+ message.FromUserName +']]></ToUserName>'+
                    '<FromUserName><![CDATA['+ message.ToUserName +']]></FromUserName>'+
                    '<CreateTime>'+createTime+'</CreateTime>'+
                    '<MsgType><![CDATA[text]]></MsgType>'+
                    '<Content><![CDATA[终于等到你,还好我没放弃]]></Content>'+
                    '</xml>'
        return;
    }
}

注:这里只是简单地实现一下自动回复功能,这种拼接字符串的方式还是很不方便的,后面会封装成接口。
使用手机微信扫描测试账号的二维码,即可关注,同时接收到测试公众号推送的消息!

图片描述

啦啦,一个简单的关注回复就完成了。

关注公众号【好便宜】( ID:haopianyi222 ),领红包啦~
阿里云,国内最大的云服务商,注册就送数千元优惠券:https://t.cn/AiQe5A0g
腾讯云,良心云,价格优惠: https://t.cn/AieHwwKl
搬瓦工,CN2 GIA 优质线路,搭梯子、海外建站推荐: https://t.cn/AieHwfX9
扫一扫关注公众号添加购物返利助手,领红包
Comments are closed.

推荐使用阿里云服务器

超多优惠券

服务器最低一折,一年不到100!

朕已阅去看看