美文网首页
nodejs实现微信公众号基本事件推回复

nodejs实现微信公众号基本事件推回复

作者: Evtion | 来源:发表于2017-06-16 22:04 被阅读0次

    微信公众号开发,微信官方只开放了个人订阅号给个人开发者,很多事件推送接口都有限制,所以自己申请了一个测试号,相对于个人未认证的订阅号,多了一些接口,下面就微信开发者文档,用Nodejs的express框架实现了基本的事件回复,利用一些普通的api实现微信公众号常见的功能。代码方面没有使用市面比较流行的wechat和wechat-api开发框架,纯粹使用原生的消息模板进行事件的回复。

    • 准备工作:

      • 微信公众号的开发需要一台公网可以访问的服务器,现在百度BAE,腾讯的服务器,阿里云的ECS对于学生都具有优惠活动,国外的AWS更有新用户免费一年的活动。自己买的是阿里云学生优惠ECS,价格是¥9.9;关于阿里云服务器的配置可以直接参考其他教程。
      • 微信公众号的域名验证,可以参考上一遍文件,关于微信接入指南。
    • 对于微信各种事件回复的代码如下:

      • 对于微信事件回复的代码如下:
    var express = require('express');
    var path = require('path');
    var favicon = require('serve-favicon');
    var logger = require('morgan');
    var xmlParse=require('xml2js').parseString;
    var cookieParser = require('cookie-parser');
    var bodyParser = require('body-parser');
    var sha1=require('sha1');
    var routes = require('./routes/index');
    var users = require('./routes/users');
    var common=require('./common');
    var request=require('request');
    var app = express();
    var data='';
    // view engine setup
    app.set('views', path.join(__dirname, 'views'));
    app.set('view engine', 'jade');
    
    // uncomment after placing your favicon in /public
    //app.use(favicon(path.join(__dirname, 'public', 'favicon.ico')));
    app.use(logger('dev'));
    app.use(bodyParser.json());
    app.use(bodyParser.urlencoded({ extended: false }));
    app.use(cookieParser());
    app.use(express.static(path.join(__dirname, 'public')));
    
    app.use('/', routes);
    app.use('/users', users);
    app.get('/validate',(req,res,next)=>{
        let token='wechat';
        let signature=req.query.signature;
        let timestamp=req.query.timestamp;
        let echostr=req.query.echostr;
        let nonce=req.query.nonce;
        let oriArray=new Array();
        oriArray.push(nonce);
        oriArray.push(timestamp);
        oriArray.push(token);
        let original=oriArray.sort().join('');
        let combineStr=sha1(original);
        if(signature==combineStr){
            res.send(echostr);
        }else{
            console.log('error');
        }
        next();
    });
    //对于各种微信服务器的事件推送进行回复
    app.post('/validate',(req,res,next)=>{
        var data='';
        req.on('data',(chunk)=>{
            data+=chunk;
        });
        req.on('end',()=>{
            xmlParse(data,(err,result)=>{
                if(result.xml.MsgType=='event'){
                    if(result.xml.Event=='subscribe'){
                        common.dealText('欢迎关注聊天小喵;\n 1.发送地址定位信息可以获得当地天气情况哟\n 2.发送歌曲名字可以获取想要听的歌哟\n3.发送语音信息可以直接小喵聊天哟,她会很多东西哟\n图片,视频识别功能还在开发中\n',res,result);
                    }else if(result.xml.Event=='CLICK' && result.xml.EventKey=='V1001_IT_NEWS'){
                        common.requestMsg('https://api.tianapi.com/it/?key=APIkey&num=2',result,res);//API
    key是天行数据的新闻apikey
                    }else if(result.xml.Event=='CLICK' && result.xml.EventKey=='V1001_TRAVEL_NEWS'){
                        common.requestMsg('https://api.tianapi.com/travel/?key=APIkey&num=2',result,res);//如上
                    }else if(result.xml.Event=='CLICK' && result.xml.EventKey=='V1001_VR_NEWS'){
                        common.requestMsg('https://api.tianapi.com/vr/?key=APIkey&num=2',result,res);//如上
                    }else if(result.xml.Event=='CLICK' && result.xml.EventKey=='V1001_AMUSE_NEWS'){
                        common.requestMsg('https://api.tianapi.com/huabian/?key=APIkey&num=2',result,res);
                    }
                }
                if(result.xml.MsgType=='location'){
                        let lat=(result.xml.Location_X);
                        let log=(result.xml.Location_Y);
                        const url='http://api.yytianqi.com/forecast7d?city='+lat+','+log+'&key=APIKEY';
                        common.requestWeather(url,result,res);                  
                }
                if(result.xml.MsgType=='image'){
                    let str= '<xml><ToUserName><![CDATA['+result.xml.FromUserName+']]></ToUserName><FromUserName><![CDATA['+result.xml.ToUserName+']]></FromUserName><CreateTime>'+new Date().getTime()+'</CreateTime><MsgType><![CDATA['+'image'+']]></MsgType><Image><MediaId><![CDATA['+result.xml.MediaId+']]></MediaId></Image></xml>';
                    res.send(str);
                }
                if(result.xml.MsgType=='text'){
                    let responseMSg=(result.xml.Content).toString();
                    let url=encodeURI("http://s.music.163.com/search/get?type=1&limit=10&offset=0&s="+responseMSg);
                    common.requestSong(url,result,res);     
                }
                if(result.xml.MsgType=='voice'){
                    let url='http://www.tuling123.com/openapi/api?key=APIKEY&info='+encodeURI(result.xml.Recognition.toString());
                    common.requestRobot(url,result,res);    
                }
    
                if(result.xml.MsgType=='video'){
                    let str='<xml><ToUserName><![CDATA['+result.xml.FromUserName+']]></ToUserName><FromUserName><![CDATA['+result.xml.ToUserName+']]></FromUserName><CreateTime>'+new Date().getTime()+'</CreateTime><MsgType><![CDATA['+'video'+']]></MsgType><Video><MediaId><![CDATA['+result.xml.MediaId+']]></MediaId><Title><![CDATA['+'video_info'+']]></Title><Description><![CDATA['+'information'+']]></Description></Video></xml>'
                    res.send(str);
                }
    
            });
        });
    
    });
    // catch 404 and forward to error handler
    app.use(function(req, res, next) {
      var err = new Error('Not Found');
      err.status = 404;
      next(err);
    });
    
    // error handlers
    
    // development error handler
    // will print stacktrace
    if (app.get('env') === 'development') {
      app.use(function(err, req, res, next) {
        res.status(err.status || 500);
        res.render('error', {
          message: err.message,
          error: err
        });
      });
    }
    
    // production error handler
    // no stacktraces leaked to user
    app.use(function(err, req, res, next) {
      res.status(err.status || 500);
      res.render('error', {
        message: err.message,
        error: {}
      });
    });
    
    
    module.exports = app;
    
    - 各种事件回复函数模块文件
    
    var request=require('request');
    //click事件推送
    function requestMsg(url,result,res){
        request(url,(err,response,body)=>{
            let data=JSON.parse(body);
            let arr=data.newslist;
            let str='<xml><ToUserName><![CDATA['+result.xml.FromUserName+']]></ToUserName><FromUserName><![CDATA['+result.xml.ToUserName+']]></FromUserName><CreateTime>'+new Date().getTime()+'</CreateTime><MsgType><![CDATA['+'news'+']]></MsgType><ArticleCount>'+'2'+'</ArticleCount><Articles><item><Title><![CDATA['+arr[0].title+']]></Title> <Description><![CDATA['+arr[0].description+']]></Description><PicUrl><![CDATA['+arr[0].picUrl+']]></PicUrl><Url><![CDATA['+arr[0].url+']]></Url></item><item><Title><![CDATA['+arr[1].title+']]></Title><Description><![CDATA['+arr[1].deacription+']]></Description><PicUrl><![CDATA['+arr[1].picUrl+']]></PicUrl><Url><![CDATA['+arr[1].url+']]></Url></item></Articles></xml>';
            res.send(str);
        });
    }
    //地理位置事件处理
    function requestWeather(url,result,res){
        request(url,(err,response,body)=>{
            if(err){
                console.log(err);
            }
    
            data=JSON.parse(body);
            dealText('城市: '+data.data.cityName+'\n时间:'+data.data.sj+'\n天气情况:'+data.data.list[0].tq1+'\n白天温度:'+data.data.list[0].qw1+'度\n夜间温度'+data.data.list[0].qw2+'度\n白天风向 :'+data.data.list[0].fx1+'\n夜间风向:'+data.data.list[0].fx2+'\n',res,result);
        });
    }
    //处理文本点歌
    function requestSong(url,result,res){
        request(url, function (error, response, body) {
                if(error){
                    dealText('出错请重试!',res,result);
                 }else if (!error && response.statusCode == 200) {
                    var data=JSON.parse(body);
                    if(data.result){
                        let url=data.result.songs[0].audio;
                        console.log(url);
                        request(url,(error, response, body)=>{
                            if(response["headers"]["content-type"]=='text/html'){
                                dealText('没有资源,请选择其他歌曲',res,result);
                            }else{
                                let picUrl=data.result.songs[0].album.picUrl;
                                let str='<xml><ToUserName><![CDATA['+result.xml.FromUserName+']]></ToUserName><FromUserName><![CDATA['+result.xml.ToUserName+']]></FromUserName><CreateTime>'+new Date().getTime()+'</CreateTime><MsgType><![CDATA['+'music'+']]></MsgType><Music><Title><![CDATA['+data.result.songs[0].name+']]></Title><Description><![CDATA['+'悠悠音乐,缕缕动听'+']]></Description><MusicUrl><![CDATA['+url+']]></MusicUrl><HQMusicUrl><![CDATA['+url+']]></HQMusicUrl><ThumbMediaId><![CDATA['+'ojH9Q9iDl50J6PjyFmQcYYKg51COLtm2SJpFdDFzR0jYNYt4JOjtfee0LKNDYzQa'+']]></ThumbMediaId></Music></xml>';
                                res.send(str);
                            }
                            
                        });     
                        
                    }else{
                       dealText('发送歌曲名字不合法,请重试',res,result);
                    }
                }
    
        });
    }
    function requestRobot(url,result,res){
        request(url,(error,response,body)=>{
            if(!error && response.statusCode==400){
                dealText('智能小喵我病了,病好了再和你聊天。。。',res,result);
            }
            let data=JSON.parse(body);
            if(data.url){
                dealText(data.text+data.url,res,result);
            }else{
                dealText(data.text,res,result);
            }
            
        });
    }
    function dealText(responseMSg,res,result){
            let str='<xml><ToUserName><![CDATA['+result.xml.FromUserName+']]></ToUserName><FromUserName><![CDATA['+result.xml.ToUserName+']]></FromUserName><CreateTime>'+new Date().getTime()+'</CreateTime><MsgType><![CDATA['+'text'+']]></MsgType><Content><![CDATA['+responseMSg+']]></Content></xml>';
            res.send(str);
    }
    exports.requestSong=requestSong;
    exports.requestWeather=requestWeather;
    exports.requestMsg=requestMsg;
    exports.dealText=dealText;
    exports.requestRobot=requestRobot;
    
    • 实现的功能效果图如下所示:
    微信公众号效果图
    • 微信测试号开发实例代码如上所示现在已经实现卫星自定义菜单,文本消息回复,语音消息回复,地理位置事件回复,已经图灵机器人接入,语音识别功能的实现

    源代码地址微信公众号开发.觉得有帮助,点个star哟。

    相关文章

      网友评论

          本文标题:nodejs实现微信公众号基本事件推回复

          本文链接:https://www.haomeiwen.com/subject/bmnmqxtx.html