The message types in WeChat are: text, picture, voice, video, geographical location, link and event message. Except for event messages, the others are collectively called ordinary messages. The push and response of messages in WeChat are transmitted in xml data packets. When a user sends a message to an official account, if the WeChat server does not receive a response within five seconds, it will disconnect and re-initiate the request, retrying a total of three times. Ordinary messages can be deduplicated using msgid to avoid the impact of duplicate messages on business logic.
If the server cannot guarantee to process and reply within five seconds, you can directly reply with an empty string. The WeChat server will not process this request and will not initiate a retry. It should be noted that the reply to the empty string mentioned here is not to reply to an empty text message, but to respond directly to Response.Write("").
The following is a brief explanation of each common message.
<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>
<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>
<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><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>
<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>
<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>
Careful programmers should have discovered that all messages (including event messages) contain the following fields
Parameter | Description |
---|---|
ToUserName | Receiver’s WeChat ID |
FromUserName | Sender’s WeChat ID, if it is normal The user is an OpenID |
CreateTime | Message creation time |
MsgType | Message type |
The types of messages have been mentioned at the beginning of the article, they are: text, image, voice, video, geographical location (location), link (link), event (event)
In order to facilitate management and code writing, we can write an enumeration for these message types. As follows:
/// <summary> /// 消息类型枚举 /// </summary> public enum MsgType { /// <summary> ///文本类型 /// </summary> TEXT, /// <summary> /// 图片类型 /// </summary> IMAGE, /// <summary> /// 语音类型 /// </summary> VOICE, /// <summary> /// 视频类型 /// </summary> VIDEO, /// <summary> /// 地理位置类型 /// </summary> LOCATION, /// <summary> /// 链接类型 /// </summary> LINK, /// <summary> /// 事件类型 /// </summary> EVENT }
Let me explain here, event is a keyword in C#, so event cannot be used in enumerations, so for the sake of uniformity, I use all uppercase for enumerations here.
Since all message bodies have the above fields, you can write a base class, and then different message entities inherit this base class. (I have been struggling with a problem. I used to write all the fields in the message body in a class, which is very convenient to call. However, there are more and more fields in the class, which makes me uncomfortable. In addition, I I have little knowledge and object-oriented and am not proficient in using it, so I always list all the fields in a class
When calling, directly var ss = WeiXinRequest.RequestHelper(token, EncodingAESKey, appid ; The readability has been improved, but calling it is not as convenient as before. Friends, please give me some suggestions
)
The following are the base classes of each message entity:
public abstract class BaseMessage { /// <summary> /// 开发者微信号 /// </summary> public string ToUserName { get; set; } /// <summary> /// 发送方帐号(一个OpenID) /// </summary> public string FromUserName { get; set; } /// <summary> /// 消息创建时间 (整型) /// </summary> public string CreateTime { get; set; } /// <summary> /// 消息类型 /// </summary> public MsgType MsgType { get; set; } public virtual void ResponseNull() { Utils.ResponseWrite(""); } public virtual void ResText(EnterParam param, string content) { } /// <summary> /// 回复消息(音乐) /// </summary> public void ResMusic(EnterParam param, Music mu) { } public void ResVideo(EnterParam param, Video v) { } /// <summary> /// 回复消息(图片) /// </summary> public void ResPicture(EnterParam param, Picture pic, string domain) { } /// <summary> /// 回复消息(图文列表) /// </summary> /// <param name="param"></param> /// <param name="art"></param> public void ResArticles(EnterParam param, List<Articles> art) { } /// <summary> /// 多客服转发 /// </summary> /// <param name="param"></param> public void ResDKF(EnterParam param) { } /// <summary> /// 多客服转发如果指定的客服没有接入能力(不在线、没有开启自动接入或者自动接入已满),该用户会一直等待指定客服有接入能力后才会被接入,而不会被其他客服接待。建议在指定客服时,先查询客服的接入能力指定到有能力接入的客服,保证客户能够及时得到服务。 /// </summary> /// <param name="param">用户发送的消息体</param> /// <param name="KfAccount">多客服账号</param> public void ResDKF(EnterParam param, string KfAccount) { } private void Response(EnterParam param, string data) { } }
/// <summary> /// 微信接入参数 /// </summary> public class EnterParam { /// <summary> /// 是否加密 /// </summary> public bool IsAes { get; set; } /// <summary> /// 接入token /// </summary> public string token { get; set; } /// <summary> ///微信appid /// </summary> public string appid { get; set; } /// <summary> /// 加密密钥 /// </summary> public string EncodingAESKey { get; set; } }
public class TextMessage:BaseMessage { /// <summary> /// 消息内容 /// </summary> public string Content { get; set; } /// <summary> /// 消息id,64位整型 /// </summary> public string MsgId { get; set; } }
public class ImgMessage : BaseMessage { /// <summary> /// 图片路径 /// </summary> public string PicUrl { get; set; } /// <summary> /// 消息id,64位整型 /// </summary> public string MsgId { get; set; } /// <summary> /// 媒体ID /// </summary> public string MediaId { get; set; } }
public class VoiceMessage : BaseMessage { /// <summary> /// 缩略图ID /// </summary> public string MsgId { get; set; } /// <summary> /// 格式 /// </summary> public string Format { get; set; } /// <summary> /// 媒体ID /// </summary> public string MediaId { get; set; } /// <summary> /// 语音识别结果 /// </summary> public string Recognition { get; set; } }
public class VideoMessage : BaseMessage { /// <summary> /// 缩略图ID /// </summary> public string ThumbMediaId { get; set; } /// <summary> /// 消息id,64位整型 /// </summary> public string MsgId { get; set; } /// <summary> /// 媒体ID /// </summary> public string MediaId { get; set; } }
public class LinkMessage : BaseMessage { /// <summary> /// 缩略图ID /// </summary> public string MsgId { get; set; } /// <summary> /// 标题 /// </summary> public string Title { get; set; } /// <summary> /// 描述 /// </summary> public string Description { get; set; } /// <summary> /// 链接地址 /// </summary> public string Url { get; set; } }
public static T ConvertObj<T>(string xmlstr) { XElement xdoc = XElement.Parse(xmlstr); var type = typeof(T); var t = Activator.CreateInstance<T>(); foreach (XElement element in xdoc.Elements()) { var pr = type.GetProperty(element.Name.ToString()); if (element.HasElements) {//这里主要是兼容微信新添加的菜单类型。nnd,竟然有子属性,所以这里就做了个子属性的处理 foreach (var ele in element.Elements()) { pr = type.GetProperty(ele.Name.ToString()); pr.SetValue(t, Convert.ChangeType(ele.Value, pr.PropertyType), null); } continue; } if (pr.PropertyType.Name == "MsgType")//获取消息模型 { pr.SetValue(t, (MsgType)Enum.Parse(typeof(MsgType), element.Value.ToUpper()), null); continue; } if (pr.PropertyType.Name == "Event")//获取事件类型。 { pr.SetValue(t, (Event)Enum.Parse(typeof(Event), element.Value.ToUpper()), null); continue; } pr.SetValue(t, Convert.ChangeType(element.Value, pr.PropertyType), null); } return t; }
public class MessageFactory { public static BaseMessage CreateMessage(string xml) { XElement xdoc = XElement.Parse(xml); var msgtype = xdoc.Element("MsgType").Value.ToUpper(); MsgType type = (MsgType)Enum.Parse(typeof(MsgType), msgtype); switch (type) { case MsgType.TEXT: return Utils.ConvertObj<TextMessage>(xml); case MsgType.IMAGE: return Utils.ConvertObj<ImgMessage>(xml); case MsgType.VIDEO: return Utils.ConvertObj<VideoMessage>(xml); case MsgType.VOICE: return Utils.ConvertObj<VoiceMessage>(xml); case MsgType.LINK: return Utils.ConvertObj<LinkMessage>(xml); case MsgType.LOCATION: return Utils.ConvertObj<LocationMessage>(xml); case MsgType.EVENT://事件类型 { } break; default: return Utils.ConvertObj<BaseMessage>(xml); } } }
public class WxRequest { public static BaseMessage Load(EnterParam param, bool bug = true) { string postStr = ""; Stream s = VqiRequest.GetInputStream();//此方法是对System.Web.HttpContext.Current.Request.InputStream的封装,可直接代码 byte[] b = new byte[s.Length]; s.Read(b, 0, (int)s.Length); postStr = Encoding.UTF8.GetString(b);//获取微信服务器推送过来的字符串 var timestamp = VqiRequest.GetQueryString("timestamp"); var nonce = VqiRequest.GetQueryString("nonce"); var msg_signature = VqiRequest.GetQueryString("msg_signature"); var encrypt_type = VqiRequest.GetQueryString("encrypt_type"); string data = ""; if (encrypt_type=="aes")//加密模式处理 { param.IsAes = true; var ret = new MsgCrypt(param.token, param.EncodingAESKey, param.appid); int r = ret.DecryptMsg(msg_signature, timestamp, nonce, postStr, ref data); if (r != 0) { WxApi.Base.WriteBug("消息解密失败"); return null; } } else { param.IsAes = false; data = postStr; } if (bug) { Utils.WriteTxt(data); } return MessageFactory.CreateMessage(data); } }
1.
WeChat public account platform source code download
2.WeChat LaLa Takeout 2.2.4 decrypted open source version of WeChat Rubik’s Cube source code
The above is the detailed content of WeChat development for receiving text messages. For more information, please follow other related articles on the PHP Chinese website!