当普通微信用户向公众账号发消息时,微信服务器将POST消息的XML数据包到开发者填写的URL上。
请注意:
- 1、关于重试的消息排重,推荐使用msgid排重。
- 2、微信服务器在五秒内收不到响应会断掉连接,并且重新发起请求,总共重试三次。假如服务器无法保证在五秒内处理并回复,可以直接回复空串,微信服务器不会对此作任何处理,并且不会发起重试。详情请见“发送消息-被动回复消息”。
- 3、为了保证更高的安全保障,开发者可以在公众平台官网的开发者中心处设置消息加密。开启加密后,用户发来的消息会被加密,公众号被动回复用户的消息也需要加密(但开发者通过客服接口等API调用形式向用户发送消息,则不受影响)。关于消息加解密的详细说明,请见“消息加解密说明”。
各消息类型的推送XML数据包结构如下:
文本消息
1
2
3
4
5
6
7
8
|
< 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 > |
图片消息
1
2
3
4
5
6
7
8
9
|
< 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 > |
语音消息
1
2
3
4
5
6
7
8
9
|
< 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 > |
请注意,开通语音识别后,用户每次发送语音给公众号时,微信会在推送的语音消息XML数据包中,增加一个Recongnition字段 (注:由于客户端缓存,开发者开启或者关闭语音识别功能,对新关注者立刻生效,对已关注用户需要24小时生效。开发者可以重新关注此帐号进行测试)。开启语音识别后的语音XML数据包如下:
1
2
3
4
5
6
7
8
9
10
|
< 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 > < Recognition > <![CDATA[腾讯微信团队]]> </ Recognition > < MsgId >1234567890123456</ MsgId > </ xml > |
多出的字段中,Format为语音格式,一般为amr,Recognition为语音识别结果,使用UTF8编码。
视频消息
1
2
3
4
5
6
7
8
9
|
< 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 > |
小视频消息
1
2
3
4
5
6
7
8
9
|
< 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 > |
地理位置消息
1
2
3
4
5
6
7
8
9
10
11
|
< 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 > |
链接消息
1
2
3
4
5
6
7
8
9
10
|
< 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 > |
接上篇,看ResponseXML(postString);方法如下
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
|
/// <summary> /// 获取用户发送的消息 /// </summary> /// <param name="postString"></param> private void ResponseXML( string postString) { //使用XMLDocument加载信息结构 XmlDocument xmlDoc = new XmlDocument(); xmlDoc.LoadXml(postString); XmlElement rootElement = xmlDoc.DocumentElement; //获取文档的根 XmlNode MsgType = rootElement.SelectSingleNode( "MsgType" ); //获取消息的文本类型 RequestXML requestXML = new RequestXML(); //声明实例,获取各个属性并赋值 requestXML.ToUserName = rootElement.SelectSingleNode( "ToUserName" ).InnerText; //公众号 requestXML.FromUserName = rootElement.SelectSingleNode( "FromUserName" ).InnerText; //用户 requestXML.CreateTime = rootElement.SelectSingleNode( "CreateTime" ).InnerText; //创建时间 requestXML.MsgType = MsgType.InnerText; //消息类型 ///对消息的不同类型进行赋值 if (requestXML.MsgType == "text" ) { //赋值文本信息内容 requestXML.Content = rootElement.SelectSingleNode( "Content" ).InnerText; } if (requestXML.MsgType.Trim() == "location" ) { ///赋值地理位置纬度,经度,地图缩放比例,地理位置说明 requestXML.Location_X = rootElement.SelectSingleNode( "Location_X" ).InnerText; requestXML.Location_Y = rootElement.SelectSingleNode( "Location_Y" ).InnerText; requestXML.Scale = rootElement.SelectSingleNode( "Scale" ).InnerText; requestXML.Label = rootElement.SelectSingleNode( "Label" ).InnerText; } if (requestXML.MsgType.Trim().ToLower() == "event" ) { ///赋值事件名称和事件key值 requestXML.EventName = rootElement.SelectSingleNode( "Event" ).InnerText; requestXML.EventKey = rootElement.SelectSingleNode( "EventKey" ).InnerText; } if (requestXML.MsgType.Trim().ToLower() == "voice" ) { ///赋值语音识别结果,赋值之前一定要记得在开发者模式下,把语音识别功能开启,否则获取不到 requestXML.Recognition = rootElement.SelectSingleNode( "Recognition" ).InnerText; } ResponseMsg(requestXML); } |
语音识别功能开启如下:
requestXML是我单独创建的一个类,该类声明了消息中常用的属性字段,如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
|
/// <summary> /// 接收消息的实体类 /// </summary> public class RequestXML { private String toUserName = String.Empty; /// <summary> /// 本公众号 /// </summary> public String ToUserName{ get ; set ;} /// <summary> /// 用户微信号 /// </summary> public String FromUserName{ get ; set ;} /// <summary> /// 创建时间 /// </summary> public String CreateTime{ get ; set ;} /// <summary> /// 信息类型 /// </summary> public String MsgType{ get ; set ;} /// <summary> /// 信息内容 /// </summary> public String Content{ get ; set ;} /*以下为事件类型的消息特有的属性*/ /// <summary> /// 事件名称 /// </summary> public String EventName{ get ; set ;} /// <summary> /// 事件值 /// </summary> public string EventKey { get ; set ; } /*以下为图文类型的消息特有的属性*/ /// <summary> /// 图文消息的个数 /// </summary> public int ArticleCount { get ; set ; } /// <summary> /// 图文消息的标题 /// </summary> public string Title { get ; set ; } /// <summary> /// 图文消息的简介 /// </summary> public string Description { get ; set ; } /// <summary> /// 图文消息图片的链接地址 /// </summary> public string PicUrl { get ; set ; } /// <summary> /// 图文消息详情链接地址 /// </summary> public string Url { get ; set ; } /// <summary> /// 图文消息集合 /// </summary> public List<RequestXML> Articles { get ; set ;} /*以下为地理位置类型的消息特有的属性*/ /// <summary> /// 地理位置纬度 /// </summary> public String Location_X { get ; set ; } /// <summary> /// 地理位置经度 /// </summary> public String Location_Y { get ; set ; } /// <summary> /// 地图缩放比例 /// </summary> public String Scale { get ; set ; } /// <summary> /// 地图位置说明 /// </summary> public String Label { get ; set ; } /// <summary> /// 语音消息特有字段 /// </summary> public String Recognition { get ; set ; } } |
继续关注 ResponseMsg(requestXML);方法如下
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
|
private void ResponseMsg(RequestXML requestXML) { string MsgType = requestXML.MsgType; try { //根据消息类型判断发送何种类型消息 switch (MsgType) { case "text" : SendTextCase(requestXML); //发送文本消息 break ; case "event" : //发送事件消息 if (! string .IsNullOrWhiteSpace(requestXML.EventName) && requestXML.EventName.ToString().Trim().Equals( "subscribe" )) { SendWelComeMsg(requestXML); //关注时返回的图文消息 } else if (! string .IsNullOrWhiteSpace(requestXML.EventName) && requestXML.EventName.ToString().Trim().Equals( "CLICK" )) { SendEventMsg(requestXML); //发送事件消息 } break ; case "voice" : SendVoiceMsg(requestXML); //发送语音消息 break ; case "location" : //发送位置消息 SendMapMsg(requestXML); break ; default : break ; } } catch (Exception ex) { HttpContext.Current.Response.Write(ex.ToString()); } } |
先来关注发送文本消息,SendTextCase(requestXML);//发送文本消息
1
2
3
4
5
6
7
8
9
10
11
12
13
|
/// <summary> /// 发送文本 /// </summary> /// <param name="requestXML"></param> private void SendTextCase(RequestXML requestXML) { string responseContent = FormatTextXML(requestXML.FromUserName, requestXML.ToUserName, requestXML.Content); HttpContext.Current.Response.ContentType = "text/xml" ; HttpContext.Current.Response.ContentEncoding = Encoding.UTF8; HttpContext.Current.Response.Write(responseContent); HttpContext.Current.Response.End(); } |
FormatTextXML方法制定格式
1
2
3
4
5
6
7
8
9
10
11
12
13
|
/// <summary> /// 返回格式化的Xml格式内容 /// </summary> /// <param name="p1">公众号</param> /// <param name="p2">用户号</param> /// <param name="p3">回复内容</param> /// <returns></returns> private string FormatTextXML( string p1, string p2, string p3) { return "<xml><ToUserName><![CDATA[" + p1 + "]]></ToUserName><FromUserName><![CDATA[" + p2 + "]]></FromUserName><CreateTime>" + DateTime.Now.Subtract( new DateTime(1970, 1, 1, 8, 0, 0)).TotalSeconds.ToString() + "</CreateTime><MsgType><![CDATA[text]]></MsgType><Content><![CDATA[" + p3 + "]]></Content><FuncFlag>1</FuncFlag></xml>" ; } |
这样就能实现消息的应答,如果用户点击的按钮,如下代码:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
|
case "event" : //发送事件消息 if (! string .IsNullOrWhiteSpace(requestXML.EventName) && requestXML.EventName.ToString().Trim().Equals( "subscribe" )) { SendWelComeMsg(requestXML); //关注时返回的图文消息 } else if (! string .IsNullOrWhiteSpace(requestXML.EventName) && requestXML.EventName.ToString().Trim().Equals( "CLICK" )) { SendEventMsg(requestXML); //发送事件消息 } break ; /// <summary> /// 发送响应事件消息 /// </summary> /// <param name="requestXML"></param> private void SendEventMsg(RequestXML requestXML) { string keyStr = requestXML.EventKey.ToString(); switch (keyStr) { case "mypay" : SendPayDetails(requestXML); //发送薪资账单 break ; case "tianqiyubao" : SendWeaterMessage(requestXML); //发送天气预报 break ; case "kaixinyixiao" : SendKaiXinMessage(requestXML); //发送开心一笑结果集 break ; case "updateMessage" : SendUpdateMessage(requestXML); //发送修改信息链接 break ; case "yuangonghuodong" : SendYuanGongHuoDong(requestXML); //发送学生活动 break ; case "yuangongtongzhi" : SendYuanGongTongZhi(requestXML); //发送员工通知 break ; case "youwenbida" : SendWenti(requestXML); //发送员工提交问题链接 break ; case "mywen" : SendWentiList(requestXML); //发送问题列表链接 break ; case "PhoneSerices" : SendKeFuMessage(requestXML); //接入客服 break ; default : String responseContent = String.Empty; responseContent = FormatTextXML(requestXML.FromUserName, requestXML.ToUserName, "此功能暂未开放!敬请期待!" ); HttpContext.Current.Response.ContentType = "text/xml" ; HttpContext.Current.Response.ContentEncoding = Encoding.UTF8; HttpContext.Current.Response.Write(responseContent); HttpContext.Current.Response.End(); break ; } } |
SendWelComeMsg(requestXML);//关注时返回的图文消息
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
|
/// <summary> /// 发送关注时的图文消息 /// </summary> /// <param name="requestXML"></param> private void SendWelComeMsg(RequestXML requestXML) { String responseContent = String.Empty; string newdate = DateTime.Now.Subtract( new DateTime(1970, 1, 1, 8, 0, 0)).TotalSeconds.ToString(); string PUrlfileName = "http://www.deqiaohr.com.cn/weixin/welcome.jpg" ; responseContent = string .Format(Message_News_Main, requestXML.FromUserName, requestXML.ToUserName, newdate, "1" , string .Format(Message_News_Item, "欢迎关注德桥员工服务中心" , "苏州德桥人力资源创立于2002年..." , PUrlfileName, "http://www.deqiaohr.com.cn/weixin/WxGsjianjie.aspx" )); HttpContext.Current.Response.ContentType = "text/xml" ; HttpContext.Current.Response.ContentEncoding = Encoding.UTF8; HttpContext.Current.Response.Write(responseContent); HttpContext.Current.Response.End(); } |
Message_News_Main 和Message_News_Item是图文消息格式化
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
|
/// <summary> /// 返回图文消息主体 /// </summary> public static string Message_News_Main { get { return @"<xml> <ToUserName><![CDATA[{0}]]></ToUserName> <FromUserName><![CDATA[{1}]]></FromUserName> <CreateTime>{2}</CreateTime> <MsgType><![CDATA[news]]></MsgType> <ArticleCount>{3}</ArticleCount> <Articles> {4} </Articles> </xml> " ; } } /// <summary> /// 返回图文消息项 /// </summary> public static string Message_News_Item { get { return @"<item> <Title><![CDATA[{0}]]></Title> <Description><![CDATA[{1}]]></Description> <PicUrl><![CDATA[{2}]]></PicUrl> <Url><![CDATA[{3}]]></Url> </item>" ; } } /// <summary> /// 发送响应语音识别结果 /// </summary> /// <param name="requestXML"></param> private void SendVoiceMsg(RequestXML requestXML) { string responseContent = FormatTextXML(requestXML.FromUserName, requestXML.ToUserName, "您刚才说的语音消息识别结果为:" + requestXML.Recognition.ToString()); HttpContext.Current.Response.ContentType = "text/xml" ; HttpContext.Current.Response.ContentEncoding = Encoding.UTF8; HttpContext.Current.Response.Write(responseContent); HttpContext.Current.Response.End(); }<br> |
以上就是关于asp.net微信开发的第二篇,针对消息应答进行学习,之后会有更新更多关于asp.net微信开发的文章,希望大家持续关注。