微信公众号开发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         消息类型,文本为text
Content         文本消息内容
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         消息类型,图片为image
PicUrl          图片链接(由系统生成)
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         语音为voice
MediaId         语音消息媒体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[video]]></MsgType>
  <MediaId><![CDATA[media_id]]></MediaId>
  <ThumbMediaId><![CDATA[thumb_media_id]]></ThumbMediaId>
  <MsgId>1234567890123456</MsgId>
</xml>


参数说明:

参数              描述
ToUserName      开发者微信号
FromUserName    发送方帐号(一个OpenID)
CreateTime      消息创建时间 (整型)
MsgType         视频为video
MediaId         视频消息媒体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         小视频为shortvideo
MediaId         视频消息媒体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         消息类型,地理位置为location
Location_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    发送方微信号,若为普通用户,则是一个OpenID
CreateTime      消息创建时间
MsgType         消息类型,链接为link
Title           消息标题
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),及时了解最新动态。

扫描二维码立即关注

原文地址:https://www.cnblogs.com/huyong/p/10659473.html

时间: 2024-10-07 21:44:34

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

微信公众号开发C#系列-9、多公众号集中管理

1.概述 通过前面8篇关于微信开发相关文章的学习,我们已经对微信常用开发有了一个比较深入的了解.前面的文章都是基于某一特定公众号的,在现实业务中同一单位个体运营着不至一个公众号,此时就需要对多个公众号集中管理,随意切换.本篇文章主要介绍多公众号集中管理的方法.表设计.设置默认公众号.生成指定格式的URL资源服务器.刷新Access_Token等. 2.公众号集中管理的方法 我们知道操作微信公众号时微信服务器都会返回相应的信息到我们自己的中转服务器上,涉及多个微信公众号管理时,我们就需要知道是那个

微信公众号开发C#系列-1、微信公众平台注册

微信公众号简介 微信公众号分为服务号.订阅号.企业号,订阅号可以个人申请,服务号和企业号要有企业资质才可以. 我们所说的微信公众号开发主要指的是公众号的账号类型,公众号的账号类型分为订阅号.服务号.企业微信.小程序四种.关于他们之间的具体区别,官方是这样解释的 服务号:主要偏向于服务交互(功能类似12315,114,银行,提供绑定信息,服务交互),每月可群发4条消息:服务号适用人群:媒体.企业.政府或其他组织. 订阅号:主要偏向于为用户传达资讯,(功能类似报纸杂志,为用户提供新闻信息或娱乐趣事)

C#微信公众号开发系列教程三(消息体签名及加解密)

  C#微信公众号开发系列教程一(调试环境部署) C#微信公众号开发系列教程一(调试环境部署续:vs远程调试) C#微信公众号开发系列教程二(新手接入指南)    距离上一篇博文已经半个月了,本来打算每两天更新一次的,但可怜苦逼码农无日无夜的加班.第一篇博文发表后,博文视点的编辑就找到我,问我想不想出版这个系列,我当时瞬间就想到了王大锤的独白,想想真的是有点小激动,后面按照那边的要求,提交了申请书,也提交了目录,可惜文笔不行,再加上最近太忙,样稿一直没有给他,感觉挺愧疚了.真心希望能帮一下迷茫的

C#微信公众号开发系列教程五(接收事件推送与消息排重)

微信公众号开发系列教程一(调试环境部署) 微信公众号开发系列教程一(调试环境部署续:vs远程调试) C#微信公众号开发系列教程二(新手接入指南) C#微信公众号开发系列教程三(消息体签名及加解密) C#微信公众号开发系列教程四(接收普通消息) C#微信公众号开发系列教程五(接收事件推送与消息排重) 在上一篇的博文中讲到,微信的消息可以大体分为两种类型,一种是包括:文本,语音,图片等的普通消息,另一种就是本篇要将的事件类型.包括:关注/取消关注事件,扫描带参数二维码事件,上报地理位置事件,自定义菜

微信公众号开发系列-发送客服消息

下面是做微信公众号开发用到最多的两个客服消息发送类型,文本信息和图文信息. 1.发送文本消息 { "touser":"OPENID", "msgtype":"text", "text": { "content":"Hello World" } } 參数 是否必须 说明 access_token 是 调用接口凭证 touser 是 普通用户openid msgtype

微信公众号开发系列教程一(调试环境部署)

原文:微信公众号开发系列教程一(调试环境部署) 目录 C#微信公众号开发系列教程一(调试环境部署) C#微信公众号开发系列教程一(调试环境部署续:vs远程调试) C#微信公众号开发系列教程二(新手接入指南) 微信公众号火了好一阵子了,笔者算是比较早接触微信公众号开发的了,大概做了一年半了,从最开始的到处网上找demo到现在也开发一些公众号.园子里关于微信开发的教程已经数不胜数了,我也准备来凑凑热闹.一是梳理下这段时间开发的经验,二是希望能帮到想做微信开发的小伙伴们,希望大大神们吐槽的时候悠着点,

C#微信公众号开发系列教程二(新手接入指南)

http://www.cnblogs.com/zskbll/p/4093954.html 此系列前面已经更新了两篇博文了,都是微信开发的前期准备工作,现在切入正题,本篇讲解新手接入的步骤与方法,大神可直接跳过,也欢迎大神吐槽. 目录 C#微信公众号开发系列教程一(调试环境部署) C#微信公众号开发系列教程一(调试环境部署续:vs远程调试) C#微信公众号开发系列教程二(新手接入指南) 微信公众平台消息接口的工作原理大概可以这样理解:从用户端到公众号端一个流程是这样的,用户发送消息到微信服务器,微

微信公众号开发系列-开发模式创建自定义菜单

通过程序方式实现自定义菜单,通过http请求封装类交互微信自定义菜单接口 1.得到AccessToken access_token是公众号的全局唯一票据,公众号调用各接口时都需使用access_token.正常情况下access_token有效期为7200秒,重复获取将导致上次获取的access_token失效.由于获取access_token的api调用次数非常有限,建议开发者全局存储与更新access_token,频繁刷新access_token会导致api调用受限,影响自身业务. 请开发者

C#微信公众号开发系列教程六(被动回复与上传下载多媒体文件)

原文:C#微信公众号开发系列教程六(被动回复与上传下载多媒体文件) 微信公众号开发系列教程一(调试环境部署) 微信公众号开发系列教程一(调试环境部署续:vs远程调试) C#微信公众号开发系列教程二(新手接入指南) C#微信公众号开发系列教程三(消息体签名及加解密) C#微信公众号开发系列教程四(接收普通消息) C#微信公众号开发系列教程五(接收事件推送与消息排重) C#微信公众号开发系列教程六(被动回复与上传下载多媒体文件) 第四,第五章已经讲了怎么处理用户发送的消息,本章就来讲讲怎么响应用户的