微信公众号开发C#系列-7、消息管理-接收事件推送
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),及时了解最新动态。
扫描二维码立即关注
微信公众号开发C#系列-7、消息管理-接收事件推送的更多相关文章
- 微信公众号开发C#系列-11、生成带参数二维码应用场景
1.概述 我们在微信公众号开发C#系列-7.消息管理-接收事件推送章节有对扫描带参数二维码事件的处理做了讲解.本篇主要讲解通过微信公众号开发平台提供的接口生成带参数的二维码及应用场景. 微信公众号平台 ...
- 微信公众号开发C#系列-12、微信前端开发利器:WeUI
1.前言 通过前面系列文章的学习与讲解,相信大家已经对微信的开发有了一个全新的认识.后端基本能够基于盛派的第三方sdk搞定大部分事宜,剩下的就是前端了.关于手机端的浏览器的兼容性问题相信一直是开发者们 ...
- C#微信公众号开发系列教程五(接收事件推送与消息排重)
微信公众号开发系列教程一(调试环境部署) 微信公众号开发系列教程一(调试环境部署续:vs远程调试) C#微信公众号开发系列教程二(新手接入指南) C#微信公众号开发系列教程三(消息体签名及加解密) C ...
- 微信公众号开发C#系列-9、多公众号集中管理
1.概述 通过前面8篇关于微信开发相关文章的学习,我们已经对微信常用开发有了一个比较深入的了解.前面的文章都是基于某一特定公众号的,在现实业务中同一单位个体运营着不至一个公众号,此时就需要对多个公众号 ...
- 微信公众号开发C#系列-8、自定义菜单及菜单响应事件的处理
1.概述 自定义菜单能够帮助公众号丰富界面,让用户更好更快地理解公众号的功能.菜单分为默认菜单与个性化菜单.个性化菜单接口是为了帮助公众号实现灵活的业务运营,开发者可以通过该接口,让公众号的不同用户群 ...
- 微信公众号开发C#系列-1、微信公众平台注册
微信公众号简介 微信公众号分为服务号.订阅号.企业号,订阅号可以个人申请,服务号和企业号要有企业资质才可以. 我们所说的微信公众号开发主要指的是公众号的账号类型,公众号的账号类型分为订阅号.服务号.企 ...
- 微信公众号开发C#系列-2、微信公众平台接入指南
概述 微信公众平台消息接口的工作原理大概可以这样理解:从用户端到公众号端一个流程是这样的,用户发送消息到微信服务器,微信服务器将接收到的消息post到用户接入时填写的url中,在url处理程序中,首先 ...
- 微信公众号开发C#系列-6、消息管理-普通消息接受处理
1.概述 通过前面章节的学习,我们已经对微信的开发有了基本的掌握与熟悉,基本可以上手做复杂的应用了.本篇我们将详细讲解微信消息管理中普通消息的接收与处理.当普通微信用户向公众账号发消息时,微信服务器将 ...
- 微信公众号开发C#系列-5、用户和用户组管理-支持同步
1.概述 眼前时下流行的经济有个叫粉丝经济,粉丝带动收益.一个好运营良好的公众号肯定会有一大批的粉丝团,如何挖掘粉丝来产生效益,是微信营销的关键.微信公众号后台本身提供了粉丝(用户)与用户分组的管理, ...
随机推荐
- 【bzoj 1414】对称的正方形 单调队列+manacher
Description Orez很喜欢搜集一些神秘的数据,并经常把它们排成一个矩阵进行研究.最近,Orez又得到了一些数据,并已经把它们排成了一个n行m列的矩阵.通过观察,Orez发现这些数据蕴涵了一 ...
- [Usaco2009 Jan]安全路经Travel BZOJ1576 Dijkstra+树链剖分+线段树
分析: Dijkstra求最短路树,在最短路树上进行操作,详情可见上一篇博客:http://www.cnblogs.com/Winniechen/p/9042937.html 我觉得这个东西不压行写出 ...
- 【毕业】-《伯恩茅斯大学毕业证书》BU一模一样原件
☞伯恩茅斯大学毕业证书[微/Q:2544033233◆WeChat:CC6669834]UC毕业证书/联系人Alice[查看点击百度快照查看][留信网学历认证&博士&硕士&海归 ...
- Python 命令行(CLI)基础库
在 CLI 下写 UI 应用 前阵子看了一下自己去年写的 Python-视频转字符动画,感觉好糗..所以几乎把整篇文章重写了一遍.并使用 curses 库实现字符动画的播放. 但是感觉,curses ...
- 教你如何使用Java手写一个基于链表的队列
在上一篇博客[教你如何使用Java手写一个基于数组的队列]中已经介绍了队列,以及Java语言中对队列的实现,对队列不是很了解的可以我上一篇文章.那么,现在就直接进入主题吧. 这篇博客主要讲解的是如何使 ...
- 你可能不知道的jvm的类加载机制
引言:在java代码中,类型的加载.连接与初始化过程都是在程序运行期间完成的. 加载:查找并加载类的二进制数据(class文件加载到内存中) 连接:a 验证:确保被加载类的正确性. b准备:为类的静态 ...
- Django解决跨域问题
原理:浏览器的同源策略,其实我们的请求发送过去了,服务器也进行响应了,就是浏览器把响应给阻止响应而已 第一种方法jsonp 因为浏览器不对 <script> 标签里面的src属性进行阻止, ...
- .NetCore WebApi——基于JWT的简单身份认证与授权(Swagger)
上接:.NetCore WebApi——Swagger简单配置 任何项目都有权限这一关键部分.比如我们有许多接口.有的接口允许任何人访问,另有一些接口需要认证身份之后才可以访问:以保证重要数据不会泄露 ...
- 死磕 java集合之ConcurrentLinkedQueue源码分析
问题 (1)ConcurrentLinkedQueue是阻塞队列吗? (2)ConcurrentLinkedQueue如何保证并发安全? (3)ConcurrentLinkedQueue能用于线程池吗 ...
- redis的set类型!!!!
一.概述 在Redis中,我们可以将Set类型看作为没有排序的字符集合,和List类型一样,我们也可以在该类型的数据值上执行添加.删除或判断某一元素是否存在等操作.需要说明的是,这些操作的时间复杂度为 ...