TNW: TypeScript(The) + Node.js(Next) + WeChat 微信公衆號開發腳手架,支持任何 Node.js 的服務端框架javascript
測試時請本身的測試號vue
這裏說的各類消息交互是指的 開發者模式下的消息交互
若是尚未開啓開發者模式能夠參考以前寫文章 開啓公衆號開發者模式java
在 TNW 中實現微信公衆號各類消息交互很是簡單,步驟以下:git
WeChat.handleMsg(...)
方法處理分發消息MsgAdapter
接口,實現業務邏輯以及各類消息回覆開發者 URL 的 POST 方法下接收各類消息 具體實現代碼以下github
Express 示例以下:typescript
// 接收微信消息入口
app.post('/msg', function (req: any, res: any) {
console.log('post...', req.query);
// 支持多公衆號
let appId: string = req.query.appId;
if (appId) {
ApiConfigKit.setCurrentAppId(appId);
}
// 獲取簽名相關的參數用於消息解密(測試號以及明文模式無此參數)
let msgSignature = req.query.msg_signature,
timestamp = req.query.timestamp,
nonce = req.query.nonce;
//監聽 data 事件 用於接收數據
let buffer: Uint8Array[] = [];
req.on('data', function (data: any) {
buffer.push(data);
});
req.on('end', function () {
let msgXml = Buffer.concat(buffer).toString('utf-8');
// 處理消息並響應對應的回覆
// ....
});
});
複製代碼
Nest 示例以下:微信
@Post("/msg")
PostMsg(@Req() req: Request, @Res() res: Response) {
let that = this;
console.log('post...', req.query);
// 支持多公衆號
let appId: string = req.query.appId;
if (appId) {
ApiConfigKit.setCurrentAppId(appId);
}
// 獲取簽名相關的參數用於消息解密(測試號以及明文模式無此參數)
let msgSignature = req.query.msg_signature,
timestamp = req.query.timestamp,
nonce = req.query.nonce;
//監聽 data 事件 用於接收數據
let buffer: Uint8Array[] = [];
req.on('data', function (data: any) {
buffer.push(data);
});
req.on('end', function () {
let msgXml = Buffer.concat(buffer).toString('utf-8');
// 處理消息並響應對應的回覆
// ...
});
}
複製代碼
WeChat.handleMsg(msgAdapter: MsgAdapter, msgXml: string, msgSignature?: string, timestamp?: string, nonce?: string)
複製代碼
handleMsg
中包含了消息的解密、各類消息分發、消息加密、各類消息回覆。這裏就不貼源碼了,感興趣的能夠看看源碼,源碼也有詳細的註釋。架構
其中 msgXml
、msgSignature
、timestamp
、nonce
已在上面的 接收各類消息中
得到,就差 MsgAdapter
了。
MsgAdapter
接口中定義的方法以下:
export interface MsgAdapter {
// 處理文本消息
processInTextMsg(inTextMsg: InTextMsg): OutMsg;
// 處理圖片消息
processInImageMsg(inImageMsg: InImageMsg): OutMsg;
// 處理聲音消息
processInVoiceMsg(inVoiceMsg: InVoiceMsg): OutMsg;
// 處理視頻消息
processInVideoMsg(inVideoMsg: InVideoMsg): OutMsg;
// 處理小視頻消息
processInShortVideoMsg(inShortVideoMsg: InShortVideoMsg): OutMsg;
// 處理地理位置消息
processInLocationMsg(inLocationMsg: InLocationMsg): OutMsg;
// 處理連接消息
processInLinkMsg(inLinkMsg: InLinkMsg): OutMsg;
// 處理語音識別結果
processInSpeechRecognitionResults(inSpeechRecognitionResults: InSpeechRecognitionResults): OutMsg;
// 處理未定義的消息(其餘消息...小哥該擴展了)
processIsNotDefinedMsg(inNotDefinedMsg: InNotDefinedMsg): OutMsg;
// 處理關注、取消關注事件
processInFollowEvent(inFollowEvent: InFollowEvent): OutMsg;
// 處理掃碼事件
processInQrCodeEvent(inQrCodeEvent: InQrCodeEvent): OutMsg;
// 處理地理位置事件
processInLocationEvent(inLocationEvent: InLocationEvent): OutMsg;
// 處理地理位置事件
processInMenuEvent(inMenuEvent: InMenuEvent): OutMsg;
// 處理模板消息事件
processInTemplateMsgEvent(inTemplateMsgEvent: InTemplateMsgEvent): OutMsg;
// 處理搖一搖周邊事件
processInShakearoundUserShakeEvent(inShakearoundUserShakeEvent: InShakearoundUserShakeEvent): OutMsg;
}
複製代碼
InXxxxMsg
統一繼承自 InMsg
,InXxxxEvent
統一繼承自 EventInMsg
而 EventInMsg
又繼承自 InMsg
,因此在任何的 inXxxxx
中都很容易獲取到 toUserName(開發者微信號即appId)
、 fromUserName(發送方賬號openId)
。 TNW 支持多公衆,後面會使用到此 appId 來實現不一樣公衆號回覆不一樣的消息
代碼實現比較簡單就不過多介紹了,請看源碼
提醒:回覆消息時能夠對不一樣的公衆號作特殊的處理
export class MsgController implements MsgAdapter {
processInTextMsg(inTextMsg: InTextMsg): OutMsg {
let outMsg: any;
let content: string = "IJPay 讓支付觸手可及 \n\nhttps://gitee.com/javen205/IJPay";
if ("極速開發微信公衆號" == inTextMsg.getContent) {
// 多公衆號支持 分別給不一樣的公衆號發送不一樣的消息
if (ApiConfigKit.getApiConfig.getAppId == 'wx614c453e0d1dcd12') {
content = "極速開發微信公衆號 \n\nhttps://github.com/javen205/weixin_guide"
outMsg = new OutTextMsg(inTextMsg);
outMsg.setContent(content);
} else {
content = "極速開發微信公衆號 \n\nhttps://github.com/javen205/TNW"
outMsg = new OutTextMsg(inTextMsg);
outMsg.setContent(content);
}
} else if ("聚合支付" == inTextMsg.getContent) {
// 最新規則:開發者只能回覆1條圖文消息;其他場景最多可回覆8條圖文消息
outMsg = new OutNewsMsg(inTextMsg);
outMsg.addArticle("聚合支付了解下", "IJPay 讓支付觸手可及",
"https://gitee.com/javen205/IJPay/raw/master/assets/img/IJPay-t.png", "https://gitee.com/javen205/IJPay")
outMsg.addArticle("jfinal-weixin", "極速開發微信公衆號",
"https://gitee.com/javen205/IJPay/raw/master/assets/img/IJPay-t.png", "https://gitee.com/JFinal/jfinal-weixin")
} else {
// outMsg = new OutTextMsg(inTextMsg);
// outMsg.setContent(content);
// 轉發給多客服PC客戶端
outMsg = new OutCustomMsg(inTextMsg);
console.log("轉發給多客服PC客戶端");
}
return outMsg;
}
processInImageMsg(inImageMsg: InImageMsg): OutMsg {
let outMsg = new OutImageMsg(inImageMsg);
outMsg.setMediaId = inImageMsg.getMediaId;
return outMsg;
}
processInVoiceMsg(inVoiceMsg: InVoiceMsg): OutMsg {
let outMsg = new OutVoiceMsg(inVoiceMsg);
outMsg.setMediaId = inVoiceMsg.getMediaId;
return outMsg;
}
processInVideoMsg(inVideoMsg: InVideoMsg): OutMsg {
let outMsg = new OutVideoMsg(inVideoMsg);
outMsg.setMediaId = inVideoMsg.getMediaId;
outMsg.setDescription = "IJPay 讓支付觸手可及";
outMsg.setTitle = "視頻消息";
return outMsg;
}
processInShortVideoMsg(inShortVideoMsg: InShortVideoMsg): OutMsg {
let outMsg = new OutVideoMsg(inShortVideoMsg);
outMsg.setMediaId = inShortVideoMsg.getMediaId;
outMsg.setDescription = "TypeScript + Node.js 開發微信公衆號";
outMsg.setTitle = "短視頻消息";
return outMsg;
}
processInLocationMsg(inLocationMsg: InLocationMsg): OutMsg {
return this.renderOutTextMsg(inLocationMsg,
"位置消息... \n\nX:" + inLocationMsg.getLocation_X + " Y:" + inLocationMsg.getLocation_Y + "\n\n" + inLocationMsg.getLabel);
}
processInLinkMsg(inLinkMsg: InLinkMsg): OutMsg {
let text = new OutTextMsg(inLinkMsg);
text.setContent("連接頻消息..." + inLinkMsg.getUrl);
return text;
}
processInSpeechRecognitionResults(inSpeechRecognitionResults: InSpeechRecognitionResults): OutMsg {
let text = new OutTextMsg(inSpeechRecognitionResults);
text.setContent("語音識別消息..." + inSpeechRecognitionResults.getRecognition);
return text;
}
processInFollowEvent(inFollowEvent: InFollowEvent): OutMsg {
if (InFollowEvent.EVENT_INFOLLOW_SUBSCRIBE == inFollowEvent.getEvent) {
return this.renderOutTextMsg(inFollowEvent,
"感謝你的關注 麼麼噠 \n\n交流羣:114196246");
}
else if (InFollowEvent.EVENT_INFOLLOW_UNSUBSCRIBE == inFollowEvent.getEvent) {
console.error("取消關注:" + inFollowEvent.getFromUserName);
return this.renderOutTextMsg(inFollowEvent);
} else {
return this.renderOutTextMsg(inFollowEvent);
}
}
processInQrCodeEvent(inQrCodeEvent: InQrCodeEvent): OutMsg {
if (InQrCodeEvent.EVENT_INQRCODE_SUBSCRIBE == inQrCodeEvent.getEvent) {
console.debug("掃碼未關注:" + inQrCodeEvent.getFromUserName);
return this.renderOutTextMsg(inQrCodeEvent,
"感謝您的關注,二維碼內容:" + inQrCodeEvent.getEventKey);
}
else if (InQrCodeEvent.EVENT_INQRCODE_SCAN == inQrCodeEvent.getEvent) {
console.debug("掃碼已關注:" + inQrCodeEvent.getFromUserName);
return this.renderOutTextMsg(inQrCodeEvent);
} else {
return this.renderOutTextMsg(inQrCodeEvent);
}
}
processInLocationEvent(inLocationEvent: InLocationEvent): OutMsg {
console.debug("發送地理位置事件:" + inLocationEvent.getFromUserName);
return this.renderOutTextMsg(inLocationEvent,
"地理位置是:" + inLocationEvent.getLatitude);
}
processInMenuEvent(inMenuEvent: InMenuEvent): OutMsg {
console.debug("菜單事件:" + inMenuEvent.getFromUserName);
return this.renderOutTextMsg(inMenuEvent,
"菜單事件內容是:" + inMenuEvent.getEventKey);
}
processInTemplateMsgEvent(inTemplateMsgEvent: InTemplateMsgEvent): OutMsg {
console.debug("模板消息事件:" + inTemplateMsgEvent.getFromUserName + " " + inTemplateMsgEvent.getStatus);
return this.renderOutTextMsg(inTemplateMsgEvent,
"消息發送狀態:" + inTemplateMsgEvent.getStatus);
}
processInShakearoundUserShakeEvent(inShakearoundUserShakeEvent: InShakearoundUserShakeEvent): OutMsg {
console.debug("搖一搖事件:" + inShakearoundUserShakeEvent.getFromUserName + " " + inShakearoundUserShakeEvent.getUuid);
return this.renderOutTextMsg(inShakearoundUserShakeEvent,
"uuid:" + inShakearoundUserShakeEvent.getUuid);
}
processIsNotDefinedMsg(inNotDefinedMsg: InNotDefinedMsg): OutMsg {
return this.renderOutTextMsg(inNotDefinedMsg,
"未知消息");
}
renderOutTextMsg(inMsg: InMsg, content?: string): OutTextMsg {
let outMsg = new OutTextMsg(inMsg);
outMsg.setContent(content ? content : " ");
return outMsg;
}
}
複製代碼
TNW
微信公衆號開發腳手架:gitee.com/javen205/TN…IJPay
讓支付觸手可及:gitee.com/javen205/IJ…mica
工具集:gitee.com/596392912/m…Avue
一款基於 vue 可配置化的神奇框架:gitee.com/smallweigit…pig
宇宙最強微服務(架構師必備):gitee.com/log4j/pigSpringBlade
完整的線上解決方案(企業開發必備):gitee.com/smallc/Spri…