
1、概述
在微信用戶和公眾號產生交互的過程中,用戶的某些操作會使得微信服務器通過事件推送的形式通知到開發者在開發者中心處設置的服務器地址,從而開發者可以獲取到該信息。其中,某些事件推送在發生后,是允許開發者回復用戶的,某些則不允許
我們在上一篇微信公眾號開發C#系列-6、消息管理-普通消息接受處理中講到,微信的消息可以大體分為兩種類型,一種是包括:文本,語音,圖片等的普通消息,另一種就是本篇要將的事件類型。包括:關注/取消關注事件,掃描帶參數二維碼事件,上報地理位置事件,自定義菜單相關事件等,本篇一一進行講解。介於偏於內容過多易產生閱讀疲勞,對於自定義菜單相關事件的處理我們放在下一篇中講解。
這里的消息指的是傳統的微信公眾平台消息交互,微信用戶向公眾號發送消息后,公眾號回復消息給微信用戶。包括以下類型:
- 關注/取消關注事件:subscribe/unsubscribe
- 掃描帶參數二維碼事件:scan
- 上報地理位置事件:location
- 自定義菜單事件
- 點擊菜單拉取消息時的事件推送
- 點擊菜單跳轉鏈接時的事件推送
本篇主要介紹前三種。
2、實現方式
使用Senparc.Weixin框架來快速處理各種接收事件推送,實現非常簡單,自定義一個繼承MessageHandler的類,重寫這些類型的方法即可。注意:DefaultResponseMessage必須重寫,用於返回沒有處理過的消息類型(也可以用於默認消息,如幫助信息等);其中所有原OnXX的抽象方法已經都改為虛方法,可以不必每個都重寫。若不重寫,默認返回DefaultResponseMessage方法中的結果。
自定義消息處理類:
public partial class CustomMessageHandler : MessageHandler<MessageContext<IRequestMessageBase, IResponseMessageBase>>
{
public CustomMessageHandler(Stream inputStream, int maxRecordCount = 0)
: base(inputStream, null, maxRecordCount)
{
WeixinContext.ExpireMinutes = 3;
}
public override void OnExecuting()
{
//測試MessageContext.StorageData
if (CurrentMessageContext.StorageData == null)
{
CurrentMessageContext.StorageData = 0;
}
base.OnExecuting();
}
public override void OnExecuted()
{
base.OnExecuted();
CurrentMessageContext.StorageData = ((int)CurrentMessageContext.StorageData) + 1;
}
}
定義好事件處理類后,分別重寫上面提到幾種接收事件推送的事件即可。
我們可以通過重寫MessageHandler里的這幾種類型方法來處理我們的業務,當然也可以只重寫需要的部分類型,不需要的類型可以不重寫,只需要定義一個統一的DefaultResponseMessage
public override IResponseMessageBase DefaultResponseMessage(IRequestMessageBase requestMessage)
{
//所有沒有被處理的消息會默認返回這里的結果
var responseMessage = this.CreateResponseMessage<ResponseMessageText>();
responseMessage.Content = "這條消息來自DefaultResponseMessage。";
return responseMessage;
}
3、消息的去重的重要性
上一篇我們就已經提到過微信服務器在5秒內收不到響應會斷掉連接,並且重新發起請求,總共重試三次。如此以來,我們模擬有這樣一個場景:當用戶關注微信賬號時,獲取當前用戶信息,然后將信息寫到數據庫中,類似網站的注冊。假設這個關注事件中,我們需要處理比較復雜的業務邏輯。如送積分,寫用戶日志,分配用戶組等等一系列的邏輯需要執行,或者網絡環境比較復雜,無法保證5秒內響應當前用戶的操作,那如果當操作尚未完成,微信服務器又給我們的服務器推送了一條相同的關注事件,我們將再次執行我們的那些邏輯,這樣就有可能導致數據庫中出現重復的數據(有的童鞋就會說了,我在插入數據之前先判斷當前是否已經存在了,如果存在了就不執行插入的操作。我想說的是,我當初也是這樣想的,但真實的運行環境和我們的調試環境還是有差距的,直到發現數據庫中有不少重復的用戶信息時,我才發現消息去重的重要性。)。
消息的去重普通消息和事件消息是有區別的。普通消息使用msgid,而事件消息使用FromUserName + CreateTime。
4、關注/取消關注事件
用戶在關注與取消關注公眾號時,微信會把這個事件推送到開發者填寫的URL。方便開發者給用戶下發歡迎消息或者做帳號的解綁。
假如服務器無法保證在五秒內處理並回復,可以直接回復空串,微信服務器不會對此作任何處理,並且不會發起重試。
關注或取消事件推送XML數據包示例:
<xml>
<ToUserName><![CDATA[toUser]]></ToUserName>
<FromUserName><![CDATA[FromUser]]></FromUserName>
<CreateTime>123456789</CreateTime>
<MsgType><![CDATA[event]]></MsgType>
<Event><![CDATA[subscribe]]></Event>
</xml>
參數說明:
參數 描述
ToUserName 開發者微信號
FromUserName 發送方帳號(一個OpenID)
CreateTime 消息創建時間 (整型)
MsgType 消息類型,event
Event 事件類型,subscribe(訂閱)、unsubscribe(取消訂閱)
4.1 關注事件
關注事件我們只需要重寫OnEvent_SubscribeRequest事件代碼即可,如下我們返回了一個文本消息,實現代碼參考:
/// <summary>
/// 訂閱(關注)事件
/// </summary>
/// <returns></returns>
public override IResponseMessageBase OnEvent_SubscribeRequest(RequestMessageEvent_Subscribe requestMessage)
{
var responseMessage = CreateResponseMessage<ResponseMessageNews>();
foreach (var model in messageList)
{
responseMessage.Articles.Add(new Article()
{
Title = "國思公眾號",
Description = "歡迎關注國思軟件公眾號,更多內容穩步官網,多謝!",
PicUrl = "http://www.rdiframework.net/WeiXin.png",
Url = "http://www.rdiframework.net/"
});
}
return responseMessage;
}

在上面的關注事件中,用戶關注公眾號就會自動執行上面的事件代碼,我們就可以在事件代碼中做相關的業務處理,如綁定用戶分組、增加用戶到本地等等。同時推送一條歡迎消息返回到用戶手機上。
4.2 取消關注事件
取消關注事件與關注事件類似,主要是事件變成了unsubscribe(取消關注)。取消關注事件-unsubscribe的主要意義在於及時刪除網站應用中已經記錄的OpenID綁定,消除冗余數據,並且關注用戶流失的情況。
取消關注事件我們只需要重寫OnEvent_UnsubscribeRequest事件代碼即可,如下我們返回了一個文本消息,實現代碼參考:
/// <summary>
/// 退訂/取消關注
/// 實際上用戶無法收到非訂閱賬號的消息,所以這里可以隨便寫。
/// unsubscribe事件的意義在於及時刪除網站應用中已經記錄的OpenID綁定,消除冗余數據。並且關注用戶流失的情況。
/// </summary>
/// <returns></returns>
public override IResponseMessageBase OnEvent_UnsubscribeRequest(RequestMessageEvent_Unsubscribe requestMessage)
{
int returnValue = RDIFrameworkService.Instance.WeixinBasicService.UserUnsubscribeByOpenId(Id,requestMessage.FromUserName);//退
var responseMessage = base.CreateResponseMessage<ResponseMessageText>();
responseMessage.Content = "有空再來";
return responseMessage;
}
上面的代碼在用戶取消公眾號的關注時就會自動執行,可以看到我們有一行代碼針對用戶取消關注時執行的業務邏輯,同時返回了一個文本消息。實際用戶已經取消關注,返回的消息也返回不到用戶手機上的。
5、掃描帶參數二維碼事件
用戶掃描帶場景值二維碼時,可能推送以下兩種事件:
- 如果用戶還未關注公眾號,則用戶可以關注公眾號,關注后微信會將帶場景值關注事件推送給開發者。
- 如果用戶已經關注公眾號,則微信會將帶場景值掃描事件推送給開發者。
5.1 接口展示與實現方式
對於第一種上面已經講了,這里就只說明下第二種。
推送XML數據包示例:
<xml>
<ToUserName><![CDATA[toUser]]></ToUserName>
<FromUserName><![CDATA[FromUser]]></FromUserName>
<CreateTime>123456789</CreateTime>
<MsgType><![CDATA[event]]></MsgType>
<Event><![CDATA[SCAN]]></Event>
<EventKey><![CDATA[SCENE_VALUE]]></EventKey>
<Ticket><![CDATA[TICKET]]></Ticket>
</xml>
參數說明:
參數 描述
ToUserName 開發者微信號
FromUserName 發送方帳號(一個OpenID)
CreateTime 消息創建時間 (整型)
MsgType 消息類型,event
Event 事件類型,SCAN
EventKey 事件KEY值,是一個32位無符號整數,即創建二維碼時的二維碼scene_id
Ticket 二維碼的ticket,可用來換取二維碼圖片
對於生成帶參數的二維碼我們會在后面的文章中專門介紹,這兒我們了解一個這個概念。為了滿足用戶渠道推廣分析和用戶帳號綁定等場景的需要,公眾平台提供了生成帶參數二維碼的接口。使用該接口可以獲得多個帶不同場景值的二維碼,用戶掃描后,公眾號可以接收到事件推送。具體官方技術文檔可參考:生成帶參數的二維碼
目前有2種類型的二維碼:
1、臨時二維碼,是有過期時間的,最長可以設置為在二維碼生成后的30天(即2592000秒)后過期,但能夠生成較多數量。臨時二維碼主要用於帳號綁定等不要求二維碼永久保存的業務場景
2、永久二維碼,是無過期時間的,但數量較少(目前為最多10萬個)。永久二維碼主要用於適用於帳號綁定、用戶來源統計等場景。
掃描帶參數二維碼事件只需要重寫OnEvent_ScanRequest事件代碼即可,如下我們返回了一個文本消息,實現代碼參考:
public override IResponseMessageBase OnEvent_ScanRequest(RequestMessageEvent_Scan requestMessage)
{
//通過掃描關注
var responseMessage = CreateResponseMessage<ResponseMessageText>();
responseMessage.Content = responseMessage.Content ?? string.Format("歡迎關注國思軟件,通過掃描二維碼進入,場景值:{0}", requestMessage.EventKey);
return responseMessage;
}
在上面的代碼中用戶掃描了帶場景值的二維碼進入公眾號后我們返回了一個提示的文本消息。這是非常有用的功能,常用途推廣,可以根據不同的二維碼場景值分別做不同的業務處理,如可以統計關注的每一個粉絲從哪里來的,做到渠道推廣分析,但是關注的都是同一個公眾號。
5.2 生成帶參數的二維碼用途
微信公眾號生成帶參數的二維碼有何用途?
- 可以區分粉絲來源,只需要生成不同的帶參數的二維碼,把這些二維碼分別投放到各個渠道,粉絲通過這些渠道二維碼進來就可以區分粉絲來源,微號幫后台渠道粉絲列表中有粉絲數及明細;
- 粉絲通過掃描渠道二維碼關注公眾號,會打標簽分組,比如粉絲掃商店A、B的二維碼進來的, 在微信公眾號后來的用戶管理中可查看到商店A/B二維碼名下的粉絲明細及分組情況;
- 可以生成多個不同的渠道二維碼配置不同的營銷活動,設置不同的關注回復信息,讓粉絲第一時間了解活動動機,是否有興趣參與等等;
- 可以利用渠道二維碼生成功能,可以實現微信收款前關注公眾號,間接分析粉絲后續消費情況;
- 考核推廣員完成任務的進度,如以推廣名字生成多不個同的二維碼,分配給不同的推廣員,每個推廣員吸引了多少粉絲關注公眾號,微號幫后台都可以一一明細;
- 帶參數的二維碼也叫渠道二維碼或者場景二維碼,生存的數量有限,且是永久二維碼。當數量用完后可以刪除一些不用的二維碼釋放出來,二次利用。

6、上報地理位置事件
用戶同意上報地理位置后,每次進入公眾號會話時,都會在進入時上報地理位置,或在進入會話后每5秒上報一次地理位置,公眾號可以在公眾平台網站中修改以上設置。上報地理位置時,微信會將上報地理位置事件推送到開發者填寫的URL。要獲取用戶地址位置,需要在微信公眾平台開發者中心開啟上報地理位置功能,開啟之后會在用戶首次進入公眾號時,彈出是否允許上報地理位置選項,如果選擇允許則在用戶每次進入公眾號會話的時候微信會以XML形式將用戶的地理位置上報到你開發者中心填寫的URL上。
注意:用戶地理位置是被動獲取的,需用戶同意后才會上報,微信公眾平台開發不能主動獲取用戶地理位置。
推送XML數據包示例:
<xml>
<ToUserName><![CDATA[toUser]]></ToUserName>
<FromUserName><![CDATA[fromUser]]></FromUserName>
<CreateTime>123456789</CreateTime>
<MsgType><![CDATA[event]]></MsgType>
<Event><![CDATA[LOCATION]]></Event>
<Latitude>23.137466</Latitude>
<Longitude>113.352425</Longitude>
<Precision>119.385040</Precision>
</xml>
參數說明:
參數 描述
ToUserName 開發者微信號
FromUserName 發送方帳號(一個OpenID)
CreateTime 消息創建時間 (整型)
MsgType 消息類型,event
Event 事件類型,LOCATION
Latitude 地理位置緯度
Longitude 地理位置經度
Precision 地理位置精度
上報地理位置事件只需要重寫OnEvent_LocationRequest事件代碼即可,如下我們返回了一個文本消息,實現代碼參考:
public override IResponseMessageBase OnEvent_LocationRequest(RequestMessageEvent_Location requestMessage)
{
//這里是微信客戶端(通過微信服務器)自動發送過來的位置信息
var responseMessage = CreateResponseMessage<ResponseMessageText>();
responseMessage.Content = "這里寫什么都無所謂,比如:上帝愛你!";
return responseMessage;//這里也可以返回null(需要注意寫日志時候null的問題)
}
上報地理位置用處非常多,可以用維度和經度獲取城市代號,調用天氣Api,也可以用來監測企業員工的位置進行微信考勤。在微信運營的時候,用戶地理位置還是我們進行營銷策划、廣告活動投放、用戶精准營銷的重要依據。
參考文章
RDIFramework.NET — 基於.NET的快速信息化系統開發框架 — 系列目錄
RDIFramework.NET ━ .NET快速信息化系統開發框架 ━ 工作流程組件介紹
RDIFramework.NET框架SOA解決方案(集Windows服務、WinForm形式與IIS形式發布)-分布式應用
RDIFramework.NET代碼生成器全新V3.5版本發布-重大升級
一路走來數個年頭,感謝RDIFramework.NET框架的支持者與使用者,大家可以通過下面的地址了解詳情。
RDIFramework.NET官方網站:http://www.rdiframework.net/
RDIFramework.NET官方博客:http://blog.rdiframework.net/
同時需要說明的,以后的所有技術文章以官方網站為准,歡迎大家收藏!
RDIFramework.NET框架由專業團隊長期打造、一直在更新、一直在升級,請放心使用!
歡迎關注RDIFramework.net框架官方公眾微信(微信號:guosisoft),及時了解最新動態。
掃描二維碼立即關注

