首页 > 编程学习 > Node.js:微信消息回复、推送的实现
2015十月27

Node.js:微信消息回复、推送的实现

适应场景:Sails框架、微信公众号数据配置在数据库中,支持多个公众号。
1、Model定义(Waterline)
文件路径:/api/models/wx/Wx_config.js

/**
 * Created by root on 10/25/15.
 */
var moment = require('moment');
module.exports = {
  schema: true,
  autoCreatedAt: false,
  autoUpdatedAt: false,
  attributes: {
    id: {
      type: 'integer',
      autoIncrement: true,
      primaryKey: true
    },
    appname: {
      type: 'string',
      required: true
    },
    ghid: {//原始ID
      type: 'string',
      unique: true,
      required: true
    },
    appid: {
      type: 'string',
      unique: true,
      required: true
    },
    appsecret: {
      type: 'string',
      unique: true,
      required: true
    },
    encodingAESKey:{
      type: 'string',
      unique: true,
      required: true
    },
    token: {
      type: 'string',
      unique: true,
      required: true
    },
    access_token: {
      type: 'string'
    },
    expire_time: {
      type:'integer',
      defaultsTo:function(){
        return 0;
      }
    },
    createdBy:{
      type: 'integer'
    },
    createdAt:{
      type:'integer',
      defaultsTo:function(){
        return moment().format('X');
      }
    }
  }
};

2、Sails默认不支持微信xml post,改造之
文件路径:/config/http.js

rawParser: function(req, res, next) {
      switch(req.headers['content-type']) {
        case 'text/xml':
          require('body-parser').raw({ type: 'text/xml' })(req, res, next);
          break;
        default :
          next();
      }
    },
    order: [
      'startRequestTimer',
      'cookieParser',
      'session',
      'myRequestLogger',
      'rawParser',
      'bodyParser',
      'handleBodyParserError',
      'compress',
      'methodOverride',
      'poweredBy',
      '$custom',
      'router',
      'www',
      'favicon',
      '404',
      '500'
    ],

3、控制类
文件路径:/api/controllers/open/WeixinController.js
微信公众号后台配置路径:http://127.0.0.1/open/weixin/api?wxid=1

/**
 * Created by root on 10/25/15.
 */
module.exports = {
  api: function (req, res) {
    var id = req.query.wxid;
    Wx_config.findOne(id).exec(function (err, conf) {
      if (err)return res.send(200, 'fail');
      if (req.body) {
        WeixinService.loop(req, function (data) {
          if (data.type = 'text') {//用户发送纯文本
            var msg = {toUserName: data.openid, fromUserName: conf.ghid, content: 'Node.js Test...'};
            WeixinService.sendTextMsg(res, msg);//向用户回复消息
          }
        });
      }
      //签名
      if (WeixinService.checkSignature(req, conf.token)) {
        res.send(200, req.query.echostr);
      } else {
        res.send(200, 'fail');
      }
    });
  }
};

4、微信服务工具类
文件路径:/api/services/WeixinService.js

/**
 * Created by root on 10/26/15.
 */
var sha1 = require('sha1'), xml2js = require('xml2js');
module.exports = {
  /**
   * 签名验证
   * @param req
   * @param token
   * @returns {boolean}
   */
  checkSignature: function (req, token) {
    var signature = req.query.signature,
      timestamp = req.query.timestamp,
      nonce = req.query.nonce,
      echostr = req.query.echostr;
    // 按照字典排序
    var array = [token, timestamp, nonce];
    array.sort();
    // 连接
    var str = sha1(array.join(""));
    // 对比签名
    return str == signature;
  },
  /**
   * 监听用户消息
   * @param req
   * @param callback
   */
  loop: function (req, callback) {
    var body = req.body.toString('utf-8');
    var data = {};
    xml2js.parseString(body, function (err, json) {
      if (err) {
      } else {
        console.log('json::' + JSON.stringify(json));
        data.type = json.xml.MsgType;
        data.openid = json.xml.FromUserName;
        if (data.type == 'text') {
          data.txt = json.xml.Content;
        } else if (data.type == 'image') {
          data.pic = json.xml.PicUrl;
        }
        return callback(data);
      }
    });
  },
  /**
   * 发送文本消息
   * @param res
   * @param msg
   */
  sendTextMsg: function (res, msg) {
    var time = Math.round(new Date().getTime() / 1000);

    var funcFlag = msg.funcFlag ? msg.funcFlag : 0;

    var output = "" +
      "<xml>" +
      "<ToUserName><![CDATA[" + msg.toUserName + "]]></ToUserName>" +
      "<FromUserName><![CDATA[" + msg.fromUserName + "]]></FromUserName>" +
      "<CreateTime>" + time + "</CreateTime>" +
      "<MsgType><![CDATA[text]]></MsgType>" +
      "<Content><![CDATA[" + msg.content + "]]></Content>" +
      "<FuncFlag>" + funcFlag + "</FuncFlag>" +
      "</xml>";

    res.type('xml');
    res.send(output);
  },
  /**
   * 发送图文消息
   * @param res
   * @param msg
   */
  sendNewsMsg: function (res, msg) {
    var time = Math.round(new Date().getTime() / 1000);
    var articlesStr = "";
    for (var i = 0; i < msg.articles.length; i++) {
      articlesStr += "<item>" +
        "<Title><![CDATA[" + msg.articles[i].title + "]]></Title>" +
        "<Description><![CDATA[" + msg.articles[i].description + "]]></Description>" +
        "<PicUrl><![CDATA[" + msg.articles[i].picUrl + "]]></PicUrl>" +
        "<Url><![CDATA[" + msg.articles[i].url + "]]></Url>" +
        "</item>";
    }

    var funcFlag = msg.funcFlag ? msg.funcFlag : 0;
    var output = "" +
      "<xml>" +
      "<ToUserName><![CDATA[" + msg.toUserName + "]]></ToUserName>" +
      "<FromUserName><![CDATA[" + msg.fromUserName + "]]></FromUserName>" +
      "<CreateTime>" + time + "</CreateTime>" +
      "<MsgType><![CDATA[news]]></MsgType>" +
      "<ArticleCount>" + msg.articles.length + "</ArticleCount>" +
      "<Articles>" + articlesStr + "</Articles>" +
      "<FuncFlag>" + funcFlag + "</FuncFlag>" +
      "</xml>";

    res.type('xml');
    res.send(output);
  }
};

Nodejs版本:0.12.7
Sails版本:0.11.0
require相关组件,记得安装。
参考项目1:https://github.com/node-webot/wechat-api
参考项目2:https://github.com/JeremyWei/weixin_api

1,293 total views, 1 views today

本文地址:https://blog.wizzer.cn/archives/3190 , 转载请保留.

本文目前尚无任何评论.

发表评论