記一次接收微信公眾平臺推送訊息的例項

神牛003發表於2017-04-06

本章的內容來源是有朋友諮詢怎麼做微信公眾號資訊的收發訊息功能,因此本著為社群做貢獻的態度申請了個人公眾號,然後嘗試對接了一下接收公眾號內容資訊的流程;要說對接其實呢也算不上,因為個人賬號只有簡單的一些接收,被動回覆等功能資訊,不能群發和使用客服介面,所以本章主要分享的是怎麼接受資訊和被動傳送回覆資訊的例項;

在公眾平臺上繫結訊息通知接收地址

這種設定的東西,其實跟著官網設定就行了,不過本人根據官網文件一步一步設定的時候,還是遇到一些問題,因此這裡需要記錄下注意的關鍵點;首先我們登陸公眾平臺-》開發-》基本配置-》點選“修改配置”-》這個時候會出現以下截圖:

填寫上面內容的時候需要注意以下幾點:

1. 接收的url地址必須外網能訪問並且在80埠

2. 第一次儲存“伺服器配置”時,必須在接收地址中以get方式獲取的公眾平臺通知的“echostr”引數,然後返回輸出這個“echostr”值給平臺(這樣你在公眾平臺儲存服務配置的時候才能成功),這個地方官網文字描述不是很突出,不重點看的話很難發現

到此,只要做到上面兩點那麼您“伺服器配置”才能儲存成功,千萬仔細哦;

 

分享接收公眾平臺通知資訊的程式碼

 1 /// <summary>
 2         /// 接收“服務配置”時通知的資訊  格式如:signature=08c66dd8b2fd8fe43118965b336d6098642607f3&echostr=6917887702473243501&timestamp=1491458849&nonce=1123949701
 3         /// </summary>
 4         /// <returns></returns>
 5         [HttpGet]
 6         public string Get()
 7         {
 8             
 9             var echostr = Request.Query["echostr"];
10             if (string.IsNullOrWhiteSpace(echostr)) { return "別瞎搞。"; }
11 
12             var sbLog = new StringBuilder(string.Empty);
13             sbLog.Append($"method:get->echostr:{echostr}->");
14             try
15             {
16                 sbLog.Append($"QueryString:{Request.QueryString.Value}->");
17             }
18             catch (Exception ex)
19             {
20                 sbLog.Append($"異常資訊:{ex.Message}->");
21             }
22             finally
23             {
24                 PublicTool.WriteLog(sbLog.ToString());
25             }
26             return echostr;
27         }

接收post過來的使用者傳送的內容資訊,目前公眾平臺通知的型別有: text:文字訊息 image:圖形訊息 voice:語音訊息 video:視訊訊息 shortvideo:小視訊訊息 location:地理位置 link:連結訊息;

 1 /// <summary>
 2         /// 接收post過來的使用者傳送的內容資訊
 3         /// </summary>
 4         /// <returns></returns>
 5         [HttpPost]
 6         public string Post()
 7         {
 8             var sbLog = new StringBuilder(string.Empty);
 9             var now = DateTime.Now;
10             var reStr = string.Empty;  //返回資訊,1.空表示不需要再通知 2.返回正規文字內容表示回覆訊息 3.其他資訊表示需要再次通知內容
11             sbLog.Append($"method:post->");
12             try
13             {
14                 var str = string.Empty;
15                 using (var stream = Request.Body)
16                 {
17                     using (var reader = new StreamReader(stream))
18                     {
19                         str = reader.ReadToEnd();
20                     }
21                 }
22                 sbLog.Append($"str:{str}->");
23                 if (string.IsNullOrWhiteSpace(str)) { return reStr; }
24 
25                 var data = PublicTool._XmlDeserialize<xml>(str);
26                 if (data == null) { return reStr; }
27                 sbLog.Append($"ToUserName:{data.ToUserName},FromUserName:{data.FromUserName},MsgType:{data.MsgType},CreateTime:{data.CreateTime}->");
28 
29                 //訊息型別 對應列舉 MsgTypeEm
30                 switch (data.MsgType)
31                 {
32                     case "text":
33                         
34                         break;
35                     case "image":
36                         break;
37                     case "voice":
38                         break;
39                     case "video":
40                         break;
41                     case "shortvideo":
42                         break;
43 
44                     case "location":
45                         break;
46                     case "link":
47                         break;
48                 }
49 
50                 //自動回覆資訊(暫時:只有文字內容)
51                 var reHuaYu = string.Empty;
52                 if (data.Content.Contains("測試") || data.Content.Contains("ceshi"))
53                 {
54                     reHuaYu = "請儘量發一些有用的資訊!";
55                 }
56                 else if (data.Content.Contains("你好") || data.Content.Contains("您好") || data.Content.Contains("群主") || data.Content.Contains("在麼"))
57                 {
58                     reHuaYu = "您好,謝謝您的支援!";
59                 }
60 
61                 if (!string.IsNullOrWhiteSpace(reHuaYu))
62                 {
63                     reStr = string.Format(@"<xml>
64                                                 <ToUserName><![CDATA[{0}]]></ToUserName>
65                                                 <FromUserName><![CDATA[{1}]]></FromUserName>
66                                                 <CreateTime>{2}</CreateTime>
67                                                 <MsgType><![CDATA[{3}]]></MsgType>
68                                                 <Content><![CDATA[{4}]]></Content>
69                                            </xml>",
70                                            data.FromUserName,
71                                            data.ToUserName,
72                                            now,
73                                            "text",
74                                            reHuaYu);
75                 }
76             }
77             catch (Exception ex)
78             {
79                 sbLog.Append($"異常資訊:{ex.Message}->");
80             }
81             finally
82             {
83                 if (!string.IsNullOrEmpty(sbLog.ToString()))
84                 {
85                     PublicTool.WriteLog(sbLog.ToString());
86                 }
87             }
88             return reStr;
89         }

 

iis和Kestrel監聽專案埠引發的一些思考,待解惑

本次我使用的是.netcore的webapi來接收通知訊息,但是當公眾平臺有80埠限制的時候,頓時我蒙了,因為我伺服器iis上有一個專案是繫結了80埠的,這個時候如果使用Kestrel再繫結一個埠那肯定不行的;想到iis可以建立虛擬子應用程式(多個子應用程式對應一個大的網站配置,這樣80埠就可以共享了),思考著Kestrel是不是也可以呢,失望的是查了很多資料都暫時沒有涉及到或者是我沒有找到這方面的資料,因此只好放棄了;

下面分享下.netcore中我操作xml序列化和反序列方法,首先需要引入 System.Xml.Serialization :

 1  /// <summary>
 2         /// xml字串反序列化
 3         /// </summary>
 4         /// <typeparam name="T"></typeparam>
 5         /// <param name="xml"></param>
 6         /// <returns></returns>
 7         public static T _XmlDeserialize<T>(string xml) where T : class, new()
 8         {
 9             T t = default(T);
10             if (string.IsNullOrEmpty(xml)) return t;
11 
12             XmlSerializer serializer = new XmlSerializer(typeof(T));
13             using (var reader = new StringReader(xml))
14             {
15                 t = (T)serializer.Deserialize(reader);
16             }
17             return t;
18         }
19 
20         /// <summary>
21         /// xml序列化
22         /// </summary>
23         /// <param name="obj"></param>
24         /// <returns></returns>
25         public static string _XMLSerialize(object obj)
26         {
27             XmlSerializer xs = new XmlSerializer(obj.GetType());
28             StringBuilder strBuidler = new StringBuilder();
29             XmlWriterSettings setting = new XmlWriterSettings();
30             setting.OmitXmlDeclaration = true;//去掉xml版本宣告
31             using (System.Xml.XmlWriter xw = System.Xml.XmlWriter.Create(strBuidler, setting))
32             {
33                 XmlSerializerNamespaces xmlns = new XmlSerializerNamespaces();
34                 xmlns.Add(string.Empty, string.Empty);
35                 xs.Serialize(xw, obj, xmlns);
36             }
37             return strBuidler.ToString();
38         }

文字日誌

 1 /// <summary>
 2         /// 文字日誌
 3         /// </summary>
 4         /// <param name="content"></param>
 5         /// <param name="basePath"></param>
 6         public static async void WriteLog(string content, string basePath = null)
 7         {
 8             basePath = basePath ?? AppContext.BaseDirectory;
 9             var now = DateTime.Now;
10 
11             var year = now.ToString("yyyy");
12             var month = now.ToString("MM");
13             var date = now.ToString("dd");
14 
15             var fileName = $"{now.ToString("HH")}.txt";
16             var path = Path.Combine(basePath, year, month, date, fileName);
17             if (!System.IO.File.Exists(path))
18             {
19 
20                 basePath = Path.Combine(basePath, year);
21                 if (!Directory.Exists(basePath)) { Directory.CreateDirectory(basePath); }
22 
23                 basePath = Path.Combine(basePath, month);
24                 if (!Directory.Exists(basePath)) { Directory.CreateDirectory(basePath); }
25 
26                 basePath = Path.Combine(basePath, date);
27                 if (!Directory.Exists(basePath)) { Directory.CreateDirectory(basePath); }
28 
29                 path = Path.Combine(basePath, fileName);
30             }
31             using (FileStream stream = new FileStream(path, FileMode.Append, FileAccess.Write))
32             {
33                 using (var writer = new StreamWriter(stream))
34                 {
35                     await writer.WriteLineAsync($"{now.ToString("yyyy-MM-dd HH:mm:ss.fff")}:{content}");
36                 }
37             }
38         }

總結一下吧:

有點好奇為什麼微信公眾平臺使用的是xml格式資料來互動,不知道是出於什麼考慮;從介面對接上來說很簡單,就是平長的get,post方式來傳遞資料,需要注意的應該是一些細節上的問題吧;還有待解決Kestrel部署netcore時是否能建立多個子虛擬目錄問題(如果您已經知道了這個答案,請不吝賜教,謝謝);最後發一張測試的公眾號二維碼,關注後輸入:測試 或 您好,群主等資訊會有我介面返回的自動回覆資訊;

相關文章