微信公众号开发C#系列-6、消息管理-普通消息接受处理

1、概述

通过前面章节的学习,我们已经对微信的开发有了基本的掌握与熟悉,基本可以上手做复杂的应用了。本篇我们将详细讲解微信消息管理中普通消息的接收与处理。当普通微信用户向公众账号发消息时,微信服务器将POST消息的XML数据包到开发者填写的URL上。接收普通消息微信官方文档参考:接收普通消息文档API
消息接收后,就有一个处理或回复的过程,单单发送消息了没有响应也是不人性化的,下面我们就对接收到微信各类型消息分别讲解处理的方法。

2、消息接收

接收普通消息类型

当普通微信用户向公众账号发消息时,微信服务器会先接收到用户发送的消息,然后将用户消息按照指定的XML格式组装好数据,最后POST消息的XML数据包到开发者填写的URL上。

接收到的普通消息的消息类型目前有以下几种:

  1. 文本消息
  2. 图片消息
  3. 语音消息
  4. 视频消息
  5. 小视频消息
  6. 地理位置消息
  7. 链接消息

每一种消息类型都有其指定的XML数据格式,这7种消息的xml格式请到官方文档查看,有具体的格式定义和属性说明。格式很简单,基本共有属性包括ToUserName、FromUserName、CreateTime、MsgType、MsgId,并且每种类型有自己特殊的属性。

接收消息的过程其实就是获取post请求的这个xml,然后对这个xml进行分析的过程。post请求的入口还是之前提到的微信公众号接入的那个地址,整个公众号的所有请求都会走这个入口,只是接入时是get请求,其它情况下是post请求。

3、消息回复

微信服务器在将用户的消息发给公众号的开发者服务器地址后,会等待开发者服务器回复响应消息。微信服务器在五秒内收不到响应会断掉连接,并且重新发起请求,总共重试三次。

假如服务器无法保证在五秒内处理并回复,必须做出下述回复,这样微信服务器才不会对此作任何处理,并且不会发起重试(这种情况下,可以使用客服消息接口进行异步回复),否则,将出现严重的错误提示。详见下面说明:

1、(推荐方式)直接回复success

2、直接回复空串(指字节长度为0的空字符串,而不是XML结构体中content字段的内容为空)

一旦遇到以下情况,微信都会在公众号会话中,向用户下发系统提示“该公众号暂时无法提供服务,请稍后再试”

1、开发者在5秒内未回复任何内容

2、开发者回复了异常数据,比如JSON数据等

另外,请注意,回复图片等多媒体消息时需要预先通过素材管理接口上传临时素材到微信服务器,可以使用素材管理中的临时素材,也可以使用永久素材。

消息回复目前支持回复文本、图片、图文、语音、视频、音乐,每一种类型的消息都有特定的XML数据格式。这几种回复消息的xml数据格式请参考官方文档,有具体的格式定义和属性说明。格式很简单,基本共有属性包括ToUserName、FromUserName、CreateTime、MsgType,并且每种类型有自己特殊的属性。

4、各类型消息的接收与回复

使用Senparc.Weixin框架来快速处理各种接收的普通消息,实现非常简单,自定义一个继承MessageHandler的类,重写这7种类型的方法即可。注意:DefaultResponseMessage必须重写,用于返回没有处理过的消息类型(也可以用于默认消息,如帮助信息等);其中所有原OnXX的抽象方法已经都改为虚方法,可以不必每个都重写。若不重写,默认返回DefaultResponseMessage方法中的结果。
CustomMessageHandle.cs需要继承Senparc.Weixin.MP.MessageHandlers

这个抽象类,并实现部分方法。最初步的CustomMessageHandle.cs代码

可能如下:

public class CustomMessageHandler : MessageHandler<CustomMessageContext>{ public CustomMessageHandler(Stream inputStream, PostModel postModel) : base(inputStream, postModel) { } public override IResponseMessageBase DefaultResponseMessage(IRequestMessageBase requestMessage) { var responseMessage = base.CreateResponseMessage<ResponseMessageText>(); //ResponseMessageText也可以是News等其他类型 responseMessage.Content = "这条消息来自DefaultResponseMessage。"; return responseMessage; }}

我们可以看到必须要重写实现的抽象方法名为DefaultResponseMessage(),这一条信息用于返回一条的消息,假如对应类型(如语音)的微信消息没有被代码处理,那么默认会返回这里的结果。在DefaultResponseMessage()方法中,我们看到这样一句:

var responseMessage = base.CreateResponseMessage<ResponseMessageText>(); //ResponseMessageText也可以是News等其他类型

这里的CreateResponseMessage

方法即创建一个返回对象,T可以为以下类型的任意一个,分别对应了不同的返回类型:

  • ResponseMessageText - 对应文本消息
  • ResponseMessageNews - 对应图文消息
  • ResponseMessageMusic - 对应音乐消息
  • ResponseMessageXXX - 其他类型以此类推

各种类型的消息我们可以根据我们自己的业务要求进行重写回复,如果没重写就会返回默认的消息(重写默认响应的基础上)。

4.1、文本消息的接收与回复

文本消息对应的数据包XML格式如下:

<xml> <ToUserName><![CDATA[toUser]]></ToUserName> <FromUserName><![CDATA[fromUser]]></FromUserName> <CreateTime>1348831860</CreateTime> <MsgType><![CDATA[text]]></MsgType> <Content><![CDATA[this is a test]]></Content> <MsgId>1234567890123456</MsgId></xml>

参数说明:

参数 描述ToUserName 开发者微信号(直接把它当做你的公众号的微信号即可)FromUserName 发送方帐号(一个OpenID)CreateTime 消息创建时间 (整型)MsgType 消息类型,文本为textContent 文本消息内容MsgId 消息id,64位整型

处理文本消息参考代码:

/// <summary>/// 处理文字请求/// </summary>/// <returns></returns>public override IResponseMessageBase OnTextRequest(RequestMessageText requestMessage){ //注意:下面泛型ResponseMessageText即返回给客户端的类型,可以根据自己的需要填写ResponseMessageNews等不同类型。 var responseMessage = CreateResponseMessage<ResponseMessageText>(); var result = new StringBuilder(); result.AppendFormat("您刚发送了文本信息:{0}\r\n\r\n", requestMessage.Content); if (CurrentMessageContext.RequestMessages.Count > 1) { result.AppendFormat("您刚还发送了如下消息({0}/{1}):\r\n", CurrentMessageContext.RequestMessages.Count, CurrentMessageContext.StorageData); for (int i = CurrentMessageContext.RequestMessages.Count - 2; i >= 0; i--) { var historyMessage = CurrentMessageContext.RequestMessages[i]; result.AppendFormat("{0} 【{1}】{2}\r\n", historyMessage.CreateTime.ToShortTimeString(), historyMessage.MsgType.ToString(), (historyMessage is RequestMessageText) ? (historyMessage as RequestMessageText).Content : "[非文字类型]" ); } result.AppendLine("\r\n"); } result.AppendFormat("如果您在{0}分钟内连续发送消息,记录将被自动保留(当前设置:最多记录{1}条)。过期后记录将会自动清除。\r\n", WeixinContext.ExpireMinutes, WeixinContext.MaxRecordCount); result.AppendLine("\r\n"); result.AppendLine("您还可以发送【位置】【图片】【语音】【视频】等类型的信息(注意是这几种类型,不是这几个文字),查看不同格式的回复。"); responseMessage.Content = result.ToString(); return responseMessage;}

文本消息调试状态展示

文本消息回复结果展示

4.2、图片消息的接收与回复

图片消息对应的数据包XML格式如下:

<xml> <ToUserName><![CDATA[toUser]]></ToUserName> <FromUserName><![CDATA[fromUser]]></FromUserName> <CreateTime>1348831860</CreateTime> <MsgType><![CDATA[image]]></MsgType> <PicUrl><![CDATA[this is a url]]></PicUrl> <MediaId><![CDATA[media_id]]></MediaId> <MsgId>1234567890123456</MsgId></xml>

参数说明:

参数 描述ToUserName 开发者微信号FromUserName 发送方帐号(一个OpenID)CreateTime 消息创建时间 (整型)MsgType 消息类型,图片为imagePicUrl 图片链接(由系统生成)MediaId 图片消息媒体id,可以调用获取临时素材接口拉取数据。MsgId 消息id,64位整型

处理图片消息参考代码:

/// <summary>/// 处理图片请求/// </summary>/// <param name="requestMessage"></param>/// <returns></returns>public override IResponseMessageBase OnImageRequest(RequestMessageImage requestMessage){ var responseMessage = CreateResponseMessage<ResponseMessageNews>(); responseMessage.Articles.Add(new Article() { Title = "您刚才发送了图片信息", Description = "您发送的图片将会显示在边上", PicUrl = requestMessage.PicUrl, Url = "http://blog.rdiframework.net/" }); responseMessage.Articles.Add(new Article() { Title = "第二条", Description = "第二条带连接的内容", PicUrl = requestMessage.PicUrl, Url = "http://blog.rdiframework.net/" }); return responseMessage;}

在上面代码中我们返回了用户发送的图片消息,同时加上了链接地址,用户单击消息会自动跳转到指定的URL地址。

图片消息调试状态展示

图片消息回复结果展示

4.3、语音消息的接收与回复

语音消息对应的数据包XML格式如下:

<xml> <ToUserName><![CDATA[toUser]]></ToUserName> <FromUserName><![CDATA[fromUser]]></FromUserName> <CreateTime>1357290913</CreateTime> <MsgType><![CDATA[voice]]></MsgType> <MediaId><![CDATA[media_id]]></MediaId> <Format><![CDATA[Format]]></Format> <MsgId>1234567890123456</MsgId></xml>

参数 描述ToUserName 开发者微信号FromUserName 发送方帐号(一个OpenID)CreateTime 消息创建时间 (整型)MsgType 语音为voiceMediaId 语音消息媒体id,可以调用获取临时素材接口拉取数据。Format 语音格式,如amr,speex等MsgID 消息id,64位整型

参数说明:

处理语音消息参考代码:

/// <summary>/// 处理语音请求/// </summary>/// <param name="requestMessage"></param>/// <returns></returns>public override IResponseMessageBase OnVoiceRequest(RequestMessageVoice requestMessage){ //获得当前公众号 WeixinOfficialAccountEntity account = RDIFrameworkService.Instance.WeixinBasicService.GetOfficialAccountEntity(Id); var responseMessage = CreateResponseMessage<ResponseMessageMusic>(); //上传缩略图 var uploadResult = Senparc.Weixin.MP.AdvancedAPIs.MediaApi.UploadTemporaryMedia(account.AccessToken, UploadMediaFileType.image,Server.GetMapPath("~/Content/Images/weixing-ma.png")); //设置音乐信息 responseMessage.Music.Title = "天籁之音"; responseMessage.Music.Description = "播放您上传的语音"; responseMessage.Music.MusicUrl = "http://www.rdiframework.net/resource/25375532.mp3"; responseMessage.Music.HQMusicUrl = "http://www.rdiframework.net/Media/GetVoice?mediaId=" + requestMessage.MediaId; responseMessage.Music.ThumbMediaId = uploadResult.media_id; return responseMessage;}

语音消息调试状态展示

语音消息回复结果展示

4.4、视频消息的接收与回复

视频消息对应的数据包XML格式如下:

<xml> <ToUserName><![CDATA[toUser]]></ToUserName> <FromUserName><![CDATA[fromUser]]></FromUserName> <CreateTime>1357290913</CreateTime> <MsgType><![CDATA]></MsgType> <MediaId><![CDATA[media_id]]></MediaId> <ThumbMediaId><![CDATA[thumb_media_id]]></ThumbMediaId> <MsgId>1234567890123456</MsgId></xml>

参数说明:

参数 描述ToUserName 开发者微信号FromUserName 发送方帐号(一个OpenID)CreateTime 消息创建时间 (整型)MsgType 视频为videoMediaId 视频消息媒体id,可以调用获取临时素材接口拉取数据。ThumbMediaId 视频消息缩略图的媒体id,可以调用多媒体文件下载接口拉取数据。MsgId 消息id,64位整型

处理视频消息参考代码:

/// <summary>/// 处理视频请求/// </summary>/// <param name="requestMessage"></param>/// <returns></returns>public override IResponseMessageBase OnVideoRequest(RequestMessageVideo requestMessage){ var responseMessage = CreateResponseMessage<ResponseMessageText>(); responseMessage.Content = "您发送了一条视频信息,ID:" + requestMessage.MediaId; return responseMessage;}

视频消息调试状态展示

视频消息回复结果展示

4.5、小视频消息的接收与回复

视频与小视频主要区别是在MsgType上,其他的都一样。

小视频消息对应的数据包XML格式如下:

<xml> <ToUserName><![CDATA[toUser]]></ToUserName> <FromUserName><![CDATA[fromUser]]></FromUserName> <CreateTime>1357290913</CreateTime> <MsgType><![CDATA[shortvideo]]></MsgType> <MediaId><![CDATA[media_id]]></MediaId> <ThumbMediaId><![CDATA[thumb_media_id]]></ThumbMediaId> <MsgId>1234567890123456</MsgId></xml>

参数说明:

参数 描述ToUserName 开发者微信号FromUserName 发送方帐号(一个OpenID)CreateTime 消息创建时间 (整型)MsgType 小视频为shortvideoMediaId 视频消息媒体id,可以调用获取临时素材接口拉取数据。ThumbMediaId 视频消息缩略图的媒体id,可以调用获取临时素材接口拉取数据。MsgId 消息id,64位整型

处理小视频消息参考代码:

public override IResponseMessageBase OnShortVideoRequest(RequestMessageShortVideo requestMessage){ var responseMessage = this.CreateResponseMessage<ResponseMessageText>(); responseMessage.Content = "您刚才发送的是小视频"; return responseMessage;}

4.6、地理位置消息的接收与回复

地理位置消息对应的数据包XML格式如下:

<xml> <ToUserName><![CDATA[toUser]]></ToUserName> <FromUserName><![CDATA[fromUser]]></FromUserName> <CreateTime>1351776360</CreateTime> <MsgType><![CDATA[location]]></MsgType> <Location_X>23.134521</Location_X> <Location_Y>113.358803</Location_Y> <Scale>20</Scale> <Label><![CDATA[位置信息]]></Label> <MsgId>1234567890123456</MsgId></xml>

参数说明:

参数 描述ToUserName 开发者微信号FromUserName 发送方帐号(一个OpenID)CreateTime 消息创建时间 (整型)MsgType 消息类型,地理位置为locationLocation_X 地理位置维度Location_Y 地理位置经度Scale 地图缩放大小Label 地理位置信息MsgId 消息id,64位整型

处理地理位置消息参考代码:

/// <summary>/// 处理位置请求/// </summary>/// <param name="requestMessage"></param>/// <returns></returns>public override IResponseMessageBase OnLocationRequest(RequestMessageLocation requestMessage){ //返回的是图文消息,是关于地址的图文消息。 var responseLocation = base.CreateResponseMessage<ResponseMessageNews>(); var markersList = new List<BaiduMarkers>(); markersList.Add(new BaiduMarkers() { Size = BaiduMarkerSize.m, Color = "red", Label = "A", Latitude = requestMessage.Location_X, Longitude = requestMessage.Location_Y, }); var mapUrl = BaiduMapHelper.GetBaiduStaticMap(requestMessage.Location_Y, requestMessage.Location_X, 1, 13, markersList); responseLocation.Articles.Add(new Article() { Description = string.Format("您刚才发送了地理位置信息。Location_X:{0},Location_Y:{1},Scale:{2},标签:{3}", requestMessage.Location_X, requestMessage.Location_Y, requestMessage.Scale, requestMessage.Label), PicUrl = SystemInfo.WeChatSiteUrl +"/Content/Images/toplogo.png", Title = "国思软件快速开发框架-地图返回", Url = mapUrl }); return responseLocation;}

地理位置消息调试状态展示

地理位置消息回复结果展示

对于回复的消息,我们还可以单击弹出百度地图返回的位置详情,具体应用可据此扩展。
地理位置消息返回消息弹出位置图片

4.7、链接消息的接收与回复

链接消息对应的数据包XML格式如下:

<xml> <ToUserName><![CDATA[toUser]]></ToUserName> <FromUserName><![CDATA[fromUser]]></FromUserName> <CreateTime>1351776360</CreateTime> <MsgType><![CDATA[link]]></MsgType> <Title><![CDATA[公众平台官网链接]]></Title> <Description><![CDATA[公众平台官网链接]]></Description> <Url><![CDATA[url]]></Url> <MsgId>1234567890123456</MsgId></xml>

参数说明:

参数 描述ToUserName 接收方微信号FromUserName 发送方微信号,若为普通用户,则是一个OpenIDCreateTime 消息创建时间MsgType 消息类型,链接为linkTitle 消息标题Description 消息描述Url 消息链接MsgId 消息id,64位整型

链接位置消息参考代码:

/// <summary>/// 处理链接消息请求/// </summary>/// <param name="requestMessage"></param>/// <returns></returns>public override IResponseMessageBase OnLinkRequest(RequestMessageLink requestMessage){ var responseMessage = ResponseMessageBase.CreateFromRequestMessage<ResponseMessageText>(requestMessage); responseMessage.Content = string.Format(@"您发送了一条连接信息: Title:{0} Description:{1} Url:{2}", requestMessage.Title, requestMessage.Description, requestMessage.Url); return responseMessage;}

参考文章

微信公众平台技术文档-官方

Senparc.Weixin SDK + 官网示例源代码

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),及时了解最新动态。

扫描二维码立即关注

微信号:guosisoft

相关文章