运行环境
.NET
准备工作
1.在微信公众平台申请开发者。
2.功能页面完成后上传至自己的网站并能在外网正常访问该URL,端口必须为80(以下统称:目标接口)
3.在微信公众平台开启开发模式。
开发流程
1.验证签名,微信服务器会发一个GET请求到目标接口,接收参数后开始验证;具体操作请参阅官方文档"接入指南"http://mp.weixin.qq.com/wiki/index.php?title=%E6%8E%A5%E5%85%A5%E6%8C%87%E5%8D%97官方文档,讲解的很清楚,验证方法在下面的代码中有
2.首先接收微信服务器发送的请求,然后进行处理,请求为xml格式,携带公众号、发送方微信号、消息类型,消息内容等结点。
3.根据消息类型,从数据库读取相关预设内容返回,要求响应时间在5秒内,返回格式同样是xml格式。
备注
个人申请只能申请订阅号,不过只能使用基础接口,企业、事业单位或*机构可以申请服务号,申请后可以申请微信认证,认证后订阅号将获得自定义菜单接口权限,服务号将获得高级接口中所有接口权限,认证300元/次,*以及部分其他组织类型的公众帐号,免收认证费用。
输出内容一定要使用UTF-8的编码方式,否则中文会产生乱码。
如果消息中需要换行,使用\r\n来换行。
支持html的a标签,但是如果是换行是紧邻关系的话可能无法识别换行。
该文只说明一些简单的实现方式,其余操作请自行查阅微信公众平台接口文档
微信公众平台:https://mp.weixin.qq.com/
扫描二维码,添加我的微信公众号。
示例代码
1 using System; 2 using System.IO; 3 using System.Text; 4 using System.Web; 5 using System.Web.Security; 6 using System.Xml; 7 8 public class WeChat : IHttpHandler 9 { 10 public void ProcessRequest(HttpContext context) 11 { 12 weixin wx = new weixin(); 13 String postStr = String.Empty; 14 15 if (HttpContext.Current.Request.HttpMethod.ToUpper() == "POST") 16 { 17 Stream s = HttpContext.Current.Request.InputStream; 18 Byte[] b = new Byte[s.Length]; 19 s.Read(b, 0, (Int32)s.Length); 20 postStr = Encoding.UTF8.GetString(b); 21 22 if (!String.IsNullOrEmpty(postStr)) 23 { 24 wx.Handle(postStr); 25 } 26 } 27 else 28 { 29 wx.Auth(); 30 } 31 } 32 33 public bool IsReusable 34 { 35 get 36 { 37 return false; 38 } 39 } 40 } 41 42 public class weixin 43 { 44 private String Token = "改写为自己的Token"; 45 private String DefaultResponseContent = "欢迎关注小牛路过"; 46 47 public void Auth() 48 { 49 String echoStr = HttpContext.Current.Request.QueryString["echoStr"]; 50 51 if (CheckSignature()) 52 { 53 if (!String.IsNullOrEmpty(echoStr)) 54 { 55 HttpContext.Current.Response.Write(echoStr); 56 HttpContext.Current.Response.End(); 57 } 58 } 59 } 60 //处理微信公众平台POST过来的数据 61 public void Handle(String postStr) 62 { 63 XmlDocument doc = new XmlDocument(); 64 doc.LoadXml(postStr); 65 66 XmlElement rootElement = doc.DocumentElement; 67 XmlNode MsgType = rootElement.SelectSingleNode("MsgType"); 68 69 RequestXML requestXML = new RequestXML(); 70 requestXML.ToUserName = rootElement.SelectSingleNode("ToUserName").InnerText; 71 requestXML.FromUserName = rootElement.SelectSingleNode("FromUserName").InnerText; 72 requestXML.CreateTime = rootElement.SelectSingleNode("CreateTime").InnerText; 73 requestXML.MsgType = MsgType.InnerText; 74 75 if (requestXML.MsgType == "text") 76 { 77 requestXML.Content = rootElement.SelectSingleNode("Content").InnerText; 78 } 79 80 else if (requestXML.MsgType == "location") 81 { 82 requestXML.Location_X = rootElement.SelectSingleNode("Location_X").InnerText; 83 requestXML.Location_Y = rootElement.SelectSingleNode("Location_Y").InnerText; 84 requestXML.Scale = rootElement.SelectSingleNode("Scale").InnerText; 85 requestXML.MapInfo = rootElement.SelectSingleNode("Label").InnerText; 86 } 87 88 else if (requestXML.MsgType == "image") 89 { 90 requestXML.PicUrl = rootElement.SelectSingleNode("PicUrl").InnerText; 91 } 92 93 ResponseMsg(requestXML); 94 } 95 96 /// 验证微信签名 97 private bool CheckSignature() 98 { 99 String signature = HttpContext.Current.Request.QueryString["signature"]; 100 String timestamp = HttpContext.Current.Request.QueryString["timestamp"]; 101 String nonce = HttpContext.Current.Request.QueryString["nonce"]; 102 String[] ArrTmp = { Token, timestamp, nonce }; 103 104 Array.Sort(ArrTmp); 105 String tmpStr = String.Join("", ArrTmp); 106 107 tmpStr = FormsAuthentication.HashPasswordForStoringInConfigFile(tmpStr, "SHA1"); 108 tmpStr = tmpStr.ToLower(); 109 110 if (tmpStr == signature) 111 { 112 return true; 113 } 114 else 115 { 116 return false; 117 } 118 } 119 120 /// <summary> 121 /// 回复消息 122 /// </summary> 123 /// <param name="weixinXML"></param> 124 private void ResponseMsg(RequestXML requestXML) 125 { 126 String responseContent = String.Empty; 127 128 if (requestXML.MsgType == "text") 129 { 130 responseContent = FormatTextXML(requestXML.FromUserName, requestXML.ToUserName, "从数据库读取的内容"); 131 } 132 133 HttpContext.Current.Response.ContentEncoding = Encoding.UTF8; 134 HttpContext.Current.Response.Write(responseContent); 135 } 136 137 /// 返回格式化文本XML内容 138 private String FormatTextXML(String fromUserName, String toUserName, String content) 139 { 140 return "<xml><ToUserName><![CDATA[" + fromUserName + "]]></ToUserName><FromUserName><![CDATA[" + toUserName + "]]></FromUserName><CreateTime>" + ConvertDateTimeInt(DateTime.Now) + "</CreateTime><MsgType><![CDATA[text]]></MsgType><Content><![CDATA[" + content + "]]></Content><FuncFlag>1</FuncFlag></xml>"; 141 } 142 143 private int ConvertDateTimeInt(System.DateTime time) 144 { 145 System.DateTime startTime = TimeZone.CurrentTimeZone.ToLocalTime(new System.DateTime(1970, 1, 1)); 146 return (int)(time - startTime).TotalSeconds; 147 } 148 } 149 150 151 //微信请求类 152 public class RequestXML 153 { 154 private String toUserName = String.Empty; 155 156 /// <summary> 157 /// 公众号 158 /// </summary> 159 public String ToUserName 160 { 161 get { return toUserName; } 162 set { toUserName = value; } 163 } 164 165 private String fromUserName = ""; 166 167 /// <summary> 168 /// 发送方微信号 169 /// </summary> 170 public String FromUserName 171 { 172 get { return fromUserName; } 173 set { fromUserName = value; } 174 } 175 176 private String createTime = String.Empty; 177 178 /// <summary> 179 /// 创建时间 180 /// </summary> 181 public String CreateTime 182 { 183 get { return createTime; } 184 set { createTime = value; } 185 } 186 187 private String msgType = String.Empty; 188 189 /// <summary> 190 /// 信息类型 地理位置:location,文本消息:text,消息类型:image 191 /// </summary> 192 public String MsgType 193 { 194 get { return msgType; } 195 set { msgType = value; } 196 } 197 198 private String content = String.Empty; 199 200 /// <summary> 201 /// 信息内容 202 /// </summary> 203 public String Content 204 { 205 get { return content; } 206 set { content = value; } 207 } 208 209 private String location_X = String.Empty; 210 211 /// <summary> 212 /// 地理位置纬度 213 /// </summary> 214 public String Location_X 215 { 216 get { return location_X; } 217 set { location_X = value; } 218 } 219 220 private String location_Y = String.Empty; 221 222 /// <summary> 223 /// 地理位置经度 224 /// </summary> 225 public String Location_Y 226 { 227 get { return location_Y; } 228 set { location_Y = value; } 229 } 230 231 private String scale = String.Empty; 232 233 /// <summary> 234 /// 地图缩放大小 235 /// </summary> 236 public String Scale 237 { 238 get { return scale; } 239 set { scale = value; } 240 } 241 242 private String mapInfo = String.Empty; 243 244 /// <summary> 245 /// 地理位置信息 246 /// </summary> 247 public String MapInfo 248 { 249 get { return mapInfo; } 250 set { mapInfo = value; } 251 } 252 253 private String picUrl = String.Empty; 254 255 /// <summary> 256 /// 图片链接 257 /// </summary> 258 public String PicUrl 259 { 260 get { return picUrl; } 261 set { picUrl = value; } 262 } 263 }