微信二次開發(fā)已經(jīng)很火熱,php、C#获搏、java像鸡、python等關(guān)于微信后臺開發(fā)案例也是比較多。但是關(guān)于nodejs開發(fā)微信的案例比較少墓律。博主在百度上找到案例也是只字片言,關(guān)于接入微信的文章也是各類各樣。博主嘗試過各種失敗梢薪,最后才接入微信。所謂萬事開始難尝哆,博主在文章會貼出自己失敗的例子秉撇,以及后續(xù)也會推出在微信開發(fā)中遇到的錯誤。
-
申請微信公眾號
- 個人開發(fā)者只能申請未認(rèn)證的訂閱號秋泄,未認(rèn)證的訂閱號可以使用的微信API接口有限琐馆;所以個人開發(fā)者申請成功訂閱號成功后,可以直接申請免費(fèi)的測試號恒序,測試號提供的API接口比較多瘦麸,方便開發(fā)進(jìn)行測試開發(fā),測試號的使用時限是一年奸焙,一年過后會被釋放瞎暑。關(guān)于注冊公眾號的流程,開發(fā)者可以自己根據(jù)騰訊官方的提示進(jìn)行填寫与帆。
-
申請測試號
- 個人性的訂閱號很多接口是不能用的了赌;個人的訂閱號也不能認(rèn)證。所以為了體驗(yàn)微信公眾號的開發(fā)的最好方法就是申請測試號了玄糟。測試號提供了很多API接口勿她,方便我們進(jìn)行測試。登錄個人訂閱號以后阵翎,在微信開發(fā)者文檔里面有申請測試號的入口逢并。申請測試號很簡單,直接用管理員的微信掃一掃就可以直接注冊到測試號了郭卫。
-
登錄到的測試頁面如下所示:
- APPID以及APPsecret都是微信提供的砍聊,這連個值到時候是用來調(diào)用獲取access_token的,而access_token是用來取得微信一些API接口的使用的口令贰军;至于下面的url是第三方服務(wù)器地址(主要是微信服務(wù)器把用戶提交的信息轉(zhuǎn)發(fā)給的服務(wù)器處理地址玻蝌,博主買了阿里云ECS,沒有注冊域名,你們可以直接填http://192.168.x.x/deal; 這個公網(wǎng)ip是阿里云提供的俯树,后面的/deal是自己定義對的處理路由)帘腹;后面token是用來驗(yàn)證消息是否來自微信服務(wù)器,自定義许饿,例如weixin阳欲。
測試號的頁面
- 第一步進(jìn)行鏈接認(rèn)證,即是配置第三方服務(wù)器和微信服務(wù)器的鏈接陋率;按照上面一步填寫好之后球化,直接提交;提交的過程中翘贮,微信服務(wù)器將會以get的方式發(fā)送nonce(隨機(jī)數(shù))赊窥,singnature(加密后簽名),timestamp(時間戳)狸页,echostr給第三方服務(wù)器。加密算法(首先將nonce扯再、timestamp芍耘、token字典序排序,然后再轉(zhuǎn)換成字符串熄阻,最后用sha1加密斋竞,最后得到signature;我們實(shí)際就是驗(yàn)證signature是否與第三方算出來的加密簽名相等)秃殉;代碼如下所示:
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 app = express();
// 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',()=>{
// console.log(data);
xmlParse(data,(err,result)=>{
console.log(result);
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='歡迎關(guān)注聊天小喵;小喵智能已經(jīng)下線坝初,其他接口在開發(fā)中。钾军。鳄袍。喵喵喵';
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);
}
if(result.xml.MsgType=='voice'){
// let requestMsg=result.xml.Recognition;
let str='<xml><ToUserName><![CDATA['+result.xml.FromUserName+']]></ToUserName><FromUserName><![CDATA['+result.xml.ToUserName+']]></FromUserName><CreateTime>'+new Date().getTime()+'</CreateTime><MsgType><![CDATA['+'voice'+']]></MsgType><Voice><MediaId><![CDATA['+result.xml.MediaId+']]></MediaId></Voice></xml>';
res.send(str);
}
if(result.xml.MsgType=='video'){
// console.log(result.xml.MediaId);
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['+'hello'+']]></Title><Description><![CDATA['+'hello world'+']]></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;
- 運(yùn)行上述代碼,然后按下提交按鈕吏恭,驗(yàn)證配置是否正確拗小;很多時候都會是提交失敗,這個時候可以繼續(xù)按提交按鈕樱哼,如果出現(xiàn)4-5次都提交失敗哀九,那很有可能是代碼出錯,可以檢查代碼搅幅;如果第一次提交出錯阅束,有可能是網(wǎng)絡(luò)原因延遲導(dǎo)致失敗,所以繼續(xù)提交茄唐。