作者:王先榮
本文介紹如何處理微信公眾號開發中的消息與事件,包括:(1)消息(事件)概況;(2)驗證消息的真實性;(3)解析消息;(4)被動回復消息;(5)發送其他消息。
開源項目地址:http://git.oschina.net/xrwang2/xrwang.weixin.PublicAccount
本文源代碼比較分散,主要在:
http://git.oschina.net/xrwang2/xrwang.weixin.PublicAccount/blob/master/xrwang.net/WeixinInterface.ashx
http://git.oschina.net/xrwang2/xrwang.weixin.PublicAccount/blob/master/xrwang.net/Example/ParseRequestMessage.aspx.cs
http://git.oschina.net/xrwang2/xrwang.weixin.PublicAccount/tree/master/PublicAccount/RequestMessage
http://git.oschina.net/xrwang2/xrwang.weixin.PublicAccount/tree/master/PublicAccount/ResponseMessage
本文的演示地址:
(1)http://xrwang.net/Example/ParseRequestMessage.aspx
(2)關注我的公眾號,並發送消息
測試號 |
|
測試號權限多,幾乎可以測試公眾平台的所有功能。 |
我的公眾號 xrwang |
|
個人訂閱號,功能較少,不過我會特別優化。 |
1 消息(事件)概況
當普通微信用戶向公眾號發消息或者微信服務器向公眾號推送事件時,微信服務器將POST消息(事件)的XML數據包到開發者填寫的公眾號服務器URL上;公眾號服務器然后對消息作出響應。
1.1 消息的流轉過程
為了便於區分,我們將微信服務器發往公眾號服務器的消息稱為請求(Request)消息;將公眾號服務器發往微信服務器的消息稱為響應(Response)消息;將推送事件看成特殊的請求消息。
請求與響應消息的流轉過程如下圖所示:
1.2 請求消息
請求消息有很多種,我們為其一一建立了對應的類,類層次結構如下圖所示:
有些請求消息,我們可以做出響應,有些則不能,詳見下表:
消息類型 | 是否事件 | 能夠被動回復 | 備注 |
文本 | × | √ | |
圖片 | × | √ | |
聲音 | × | √ | |
視頻 | × | 未知 | 接收不到視頻消息,不知道是否能被動回復 |
地理位置 | × | √ | |
鏈接 | × | √ | |
訂閱 | √ | √ | |
取消訂閱 | √ | × | |
掃描二維碼 | √ | × | |
上報地理位置 | √ | × | |
點擊菜單拉取消息 | √ | √ | |
點擊菜單跳轉鏈接 | √ | × | |
點擊菜單掃碼推 | √ | × | |
點擊菜單掃碼等待回復 | √ | √ | |
點擊菜單系統發圖 | √ | 未知 | 接收不到系統發圖事件;微信服務器會發送圖片消息,可回復 |
點擊菜單拍照或相冊發圖 | √ | × | 微信服務器會發送圖片消息,可回復 |
點擊菜單微信發圖 | √ | × | 微信服務器會發送圖片消息,可回復 |
點擊菜單選擇地理位置 | √ | × | 微信服務器會發送地理位置消息,可回復 |
推送群發消息結果 | √ | × | |
推送發送模板消息結果 | √ | × |
1.3 響應消息
響應消息的類層次結構如下圖所示:
2 驗證消息的真實性
公眾號服務器接收到微信服務器的請求之后,第一件事情是驗證消息的真實性。
Utility.CheckSignature方法用於驗證消息簽名是否正確。
示例如下:

/// <summary> /// 驗證消息的有效性 /// </summary> /// <param name="context"></param> /// <returns>如果消息有效,返回true;否則返回false。</returns> private bool Validate(HttpContext context) { string username = RequestEx.TryGetQueryString("username"); //在接口配置的URL中加入了username參數,表示哪個微信公眾號 AccountInfo account = AccountInfoCollection.GetAccountInfo(username); if (account == null) return false; string token = account.Token; string signature = RequestEx.TryGetQueryString("signature"); string timestamp = RequestEx.TryGetQueryString("timestamp"); string nonce = RequestEx.TryGetQueryString("nonce"); if (string.IsNullOrWhiteSpace(signature) || string.IsNullOrWhiteSpace(timestamp) || string.IsNullOrWhiteSpace(nonce)) return false; return xrwang.weixin.PublicAccount.Utility.CheckSignature(signature, token, timestamp, nonce); }
3 解析消息
如果消息簽名通過驗證,我們需要將XML格式的消息文本解析成請求消息對象,RequestMessageHelper類用於完成這項工作。
RequestMessageHelper helper = new RequestMessageHelper(context.Request); if(helper.Message != null) { //消息解析成功,對它進行處理 }
消息解析成功之后,helper.Message為消息基類RequestBaseMessage,我們可以根據屬性MsgType及Event判斷到底是哪種消息(事件),並轉換成適當的子類型。例如:

RequestBaseMessage bm=helper.Message; switch(bm.MsgType) { case RequestMessageTypeEnum.text: //文本消息 HandleTextMessage((RequestTextMessage)bm); break; case RequestMessageTypeEnum.image: //圖片消息 HandleImageMessage((RequestImageMessage)bm); break; //處理其他消息 case RequestMessageTypeEnum.event: //事件 RequestEventMessage ev=(RequestEventMessage)bm; switch(ev.Event) { case RequestEventTypeEnum.subscribe: //訂閱 HandleSubscribeMessage((RequestSubscribeMessage)ev); break; case RequestEventTypeEnum.unsubscribe: //取消訂閱 HandleUnsubscribeMessage((RequestUnsubscribeMessage)ev); break; //處理其他事件 } break; default: break; }
解析消息的細節請參看源代碼:http://git.oschina.net/xrwang2/xrwang.weixin.PublicAccount/blob/master/PublicAccount/RequestMessage/RequestMessageHelper.cs
4 被動回復消息
從微信服務器接收到消息(事件)之后,我們可以在5秒之內直接(被動)回復消息;也可以先直接回復空字符串,然后再在48小時內回復客服消息。
先初始化ResponseXxxMessage,然后用ToXml方法得到響應消息內容。
被動回復消息的示例如下:

/// <summary> /// 處理微信的POST請求 /// </summary> /// <param name="context"></param> /// <returns>返回xml響應</returns> private string HandlePost(HttpContext context) { RequestMessageHelper helper = new RequestMessageHelper(context.Request); if (helper.Message != null) { ResponseBaseMessage responseMessage = HandleRequestMessage(helper.Message); return responseMessage.ToXml(helper.EncryptType); } else return string.Empty; } /// <summary> /// 處理請求消息,返回響應消息 /// </summary> /// <returns>返回響應消息</returns> private ResponseBaseMessage HandleRequestMessage(RequestBaseMessage requestMessage) { ResponseTextMessage response = new ResponseTextMessage(requestMessage.FromUserName, requestMessage.ToUserName, DateTime.Now, string.Format("自動回復,請求內容如下:\r\n{0}", requestMessage)); return response; }
5 發送其他消息
除了被動回復消息之外,我們還可以發送客服消息、群發消息、發送模板消息,這些內容將在后續文章中一一道來。
感謝您看完本文,希望對您有所幫助。