zoukankan      html  css  js  c++  java
  • Node.js+Koa开发微信公众号个人笔记(二)响应事件

    微信公众号中的事件有订阅事件/扫码事件/点击事件/跳转链接事件等等,具体可以查阅文档。

    这里来实现一下订阅事件,其他的事件的实现过程也都类似。

    当有人订阅了公众号后,微信服务器会向我们的服务器推送一个事件,这个事件是XML格式的数据包。

    一、我们在index路由下实现post事件的响应。

    可以理解为当微信向我们的服务器推送消息时,消息就会先走到这里。

    /routes/index.js加入:

    router.post('/', index_middleware.post(config.wechat));

    二、实现index_middleware中的post方法:

    就是我们该如何处理微信服务器给我们的服务器的post请求。

    大致过程是先把微信服务器发来的数据包接收到,然后解析这个XML数据包,然后根据接收来的数据,在我们服务器上进行逻辑处理后形成一个XML格式的回复消息。

    /wechat/index_middleware.js加入:

    exports.post = 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);
    
            if (sha !== signature) {
                this.body = 'wrong';
                return false;
            }
    
            var data = yield getRawBody(this.req, {
                length: this.length,
                limit: '1mb',
                encoding: this.charset
            });
    
            var message = yield util.parseXMLAsync(data);
            var xml = yield autoReply(message.xml, wechat);
            console.log(message);
            console.log(xml);
    
            this.status = 200;
            this.type = 'application/xml';
            this.body = xml;
        };
    };

    这里的data就是我们接收到的数据包,使用了raw-body这个组件。同时使用了util这个工具函数和autoReply这个自定义的函数。

    因此在/wechat/index_middleware.js中需要加入以下代码:

    var getRawBody = require('raw-body');
    var util = require('./util');
    var autoReply = require('./autoReply');

    三、实现util工具函数中的parseXMLAsync方法,它的作用是异步地将xml格式化为json数据。

    /wechat/util.js:

    var fs = require('fs');
    var xml2js = require('xml2js');
    
    exports.parseXMLAsync = function(xml) {
        return new Promise(function(resolve, reject) {
            xml2js.parseString(xml, {
                trim: true,
                explicitArray: false
            }, function(err, content) {
                if (err) {
                    reject(err);
                }
                resolve(content);
            });
        });
    };

    这里用到了xml2js这个组件。

    四、实现autoReply函数,它的作用是将微信服务器发来的数据包进行逻辑处理,形成我们需要发送给微信的XML格式数据。

    /wechat/autoReply.js:

    var createXML = require('./createXML');
    
    function autoReply(message, wechat) {
        if (message.MsgType === 'event') {
            if (message.Event === 'subscribe') {
                if (message.EventKey) {
                    console.log('扫码进入');
                }
                var now = new Date().getTime();
                return Promise.resolve(createXML({
                    ToUserName: message.FromUserName,
                    FromUserName: message.ToUserName,
                    MsgType: 'text',
                    Content: 'Hello!!'
                }));
            }else if (message.Event === 'unsubscribe') {
                console.log('取关');
                return Promise.resolve('');
            }
        }
    }

    这里只实现了关注和取关的事件,同时用到了createXML函数,它的作用是将数据封装成xml格式:

    /wechat/createXML.js:

    function createXML(messageObj) {
        var { ToUserName, FromUserName, MsgType = 'text'} = messageObj;
        var CreateTime = new Date().getTime();
        var header = `<xml>
                        <ToUserName><![CDATA[${ToUserName}]]></ToUserName>
                        <FromUserName><![CDATA[${FromUserName}]]></FromUserName>
                        <CreateTime>${CreateTime}</CreateTime>
                        <MsgType><![CDATA[${MsgType}]]></MsgType>`;
        var content = '';
        switch(MsgType) {
            case 'text':
                var { Content } = messageObj;
                content = `<Content><![CDATA[${Content}]]></Content>
                         </xml>`;
                break;
            case 'image':
                var { MediaId }  = messageObj;
                content = `<Image>
                             <MediaId><![CDATA[${MediaId}]]></MediaId>
                           </Image>
                         </xml>`;
                break;
            case 'voice':
                var { MediaId } = messageObj;
                content = `<Voice>
                             <MediaId><![CDATA[${MediaId}]]></MediaId>
                           </Voice>
                         </xml>`;
                break;
            case 'video':
                var { MediaId, Title, Description } = messageObj;
                content = `<Video>
                             <MediaId><![CDATA[${MediaId}]]></MediaId>
                             <Title><![CDATA[${Title}]]></Title>
                             <Description><![CDATA[${Description}]]></Description>
                           </Video> 
                         </xml>`;
                break;
            case 'music':
                var { Title, Description, MusicUrl, HQMusicUrl, ThumbMediaId } = messageObj;
                content = `<Music>
                             <Title><![CDATA[${Title}]]></Title>
                             <Description><![CDATA[${Description}]]></Description>
                             <MusicUrl><![CDATA[${MusicUrl}]]></MusicUrl>
                             <HQMusicUrl><![CDATA[${HQMusicUrl}]]></HQMusicUrl>
                             <ThumbMediaId><![CDATA[${ThumbMediaId}]]></ThumbMediaId>
                           </Music>
                         </xml>`;
                break;
            case 'news':
                var { Articles } = messageObj;
                var ArticleCount = Articles.length;
                content = `<ArticleCount>${ArticleCount}</ArticleCount><Articles>`;
                for (var i = 0; i < ArticleCount; i++) {
                    content += `<item>
                                    <Title><![CDATA[${Articles[i].Title}]]></Title>
                                    <Description><![CDATA[${Articles[i].Description}]]></Description>
                                    <PicUrl><![CDATA[${Articles[i].PicUrl}]]></PicUrl>
                                    <Url><![CDATA[${Articles[i].Url}]]></Url>
                                  </item>`;
                }
                content += '</Articles></xml>';
                break;
            default:
                content = `<Content><![CDATA[Error]]></Content>
                         </xml>`;
        }
        
        var xml = header + content;
        return xml;
    }
    
    module.exports = createXML;

    完成以上工作以后,启动我们的服务器,再次关注公众号,应该能收到一条Hello!!的信息。

    这样就实现了对关注事件的处理。

  • 相关阅读:
    DOS命令:列出某目录下的所有文本文件名并重定向到某文件
    换掉Tomcat默认图标
    Html中的次方符号怎么写
    MySQL插值语句
    截短字符串的函数(JS中适用)
    使用grep进行文本查找
    使用sed进行文字替换
    Carrer Day有感
    Pinger2
    Pinger
  • 原文地址:https://www.cnblogs.com/zczhangcui/p/7010709.html
Copyright © 2011-2022 走看看