Node.js微信公众号开发:实现自动回复与代码重构

作者:后端茶话时间:2026-10-23 00:28:26浏览:279

本文基于Node.js环境,详细讲解如何实现微信公众号的自动回复功能。内容涵盖将接入代码重构为[[wp:a1]]风格中间件、通过构造函数管理[[wp:a7]]的生命周期与缓存、以及接收并解析微信服务器推送的XML数据。通过具体代码示例,展示如何判断消息类型并返回文本回复,帮助开发者完善微信接口对接流程。

Node.js微信公众号自动回复实现

在上一篇文章中,我们完成了Node.js微信公众号的基础接入。本文将在此基础上,进一步实现简单的消息自动回复功能。

接入代码优化与中间件封装

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 wechat = require('./wechat/generator');

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

var app = new Koa();
app.use(wechat(config.wechat));
app.listen(8080);
console.log('Listening 8080...')

access_token获取与管理策略

2. 获取access_token

access_token是开发程序与微信公众平台进行交互的关键凭证,调用绝大多数接口时都需要使用access_token。

access_token具有以下特点:

  1. 有效期为2小时(7200秒),过期后自动失效,必须重新获取;
  2. 一旦获取了新的,之前使用的将立即失效;

针对上述特点,解决方案如下:

  1. 系统每隔2小时自动获取一次的值,确保始终处于有效状态;
  2. 为了便于频繁调用,将存储在唯一的位置(如数据库或文件),确保所有子系统均可访问。

在程序中,我们采用构造函数的方式,在生成实例并完成初始化的过程中,读取存储在config/wechat.txt文件中的票据。程序会判断票据是否为空或已过期,并选择性地重新获取票据后保存至原文件。关于获取的官方文档详情,可参考:获取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);

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

微信消息处理流程与XML解析

3. 处理微信消息的步骤

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

  1. 处理POST类型的控制逻辑,接收xml数据包;
  2. 解析数据包,获取数据包的消息类型或数据类型;
  3. 拼装自定义的消息;
  4. 包装成xml格式;
  5. 在5秒钟内返回消息。

3.1 接收xml数据

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


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

Node.js微信公众号自动回复实现

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);
    })
  });
}

Node.js微信公众号自动回复实现

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;
}

Node.js微信公众号自动回复实现

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;
  }
}

注:这里只是简单地实现一下自动回复功能,这种拼接字符串的方式还是很不方便的,后面会封装成接口。

使用手机微信扫描测试账号的二维码,即可关注,同时接收到测试公众号推送的消息!

Node.js微信公众号自动回复实现

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

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持本站。

作者最新文章