微信公眾號開發,微信官方只開放了個人訂閱號給個人開發者,很多事件推送接口都有限制,所以自己申請了一個測試號,相對于個人未認證的訂閱號,多了一些接口,下面就微信開發者文檔,用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喲。