最近因為需要用C#開發微信公眾號的一些功能,記錄一下開發公眾號的一些坑。。。。。
首先先介紹一下,微信公眾號的官方文檔。雖然這個文檔我感覺比較糙,但是還是可以借鑒一下讓我們摸着石頭過河的。
首先我們得注冊一個公眾號,配置一下公眾號的基本配置。就是將公眾號設置成開發者模式,如下圖:

下面的服務器配置就是,微信連接你的服務器的地址。比如說:用戶發送一個消息,微信會轉發到這個服務器地址,以方便開發者監聽用戶的一些信息做對應的處理。
要配置這個服務器地址,我們先來參考一下公眾號的開發文檔看看:

根據這個流程圖,我們可以知道這個服務需要先驗證一下。以下代碼是一個包括了處理用戶消息以及驗證的一個一般處理程序
public void ProcessRequest(HttpContext context)
{
Response.ContentType = "text/plain";
if (Request.HttpMethod.ToLower() == "post")
{//消息處理
using (StreamReader streamReader = new StreamReader(Request.InputStream, Encoding.UTF8))
{
var postString = streamReader.ReadToEnd();
MessageHelper messageHelper = new MessageHelper();
var responseContent = messageHelper.ResponseContent(postString);
Response.ContentEncoding = Encoding.UTF8;
Response.Write(responseContent);
}
}
else
{//驗證服務
var signature = Request.QueryString["signature"];
var timestamp = Request.QueryString["timestamp"];
var nonce = Request.QueryString["nonce"];
var echostr = Request.QueryString["echostr"];
var res = WeChatHelper.Check(signature, timestamp, nonce) ? echostr : "Verification passed";
Response.Write(res);
Response.End();
}
}
var res = WeChatHelper.Check(signature, timestamp, nonce) ? echostr : "Verification passed";這一段就是按照微信的文檔給出我們處理他的字符串並且返回一個他所需驗證的字符串,具體驗證代碼如下:
/// <summary>
/// 校驗signature
/// </summary>
/// <param name="signature"></param>
/// <param name="token"></param>
/// <param name="timestamp"></param>
/// <param name="nonce"></param>
/// <returns></returns>
public static bool Check(string signature, string timestamp, string nonce)
{
string token = "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx";
var sha1 = GetSHA1(String.Join("", new[] { token, timestamp, nonce }.OrderBy(d => d).ToArray()));//.OrderBy(d => d)字典序
return sha1 == signature;
}
這邊的token就是你配置服務上面的Token,就是將微信服務所傳過來的字符串進行排序之后拼接起來后進行SHA1加密,然后與他傳過來的signature進行比較如果相等的話就表示驗證通過,否則你配置服務的時候也會報錯的。所以配置服務的時候,需要你的服務器地址(比如發布程序后我的一般處理程序的地址),以及Token(就是這邊的咱們代碼里面的token,這個最好寫在配置文件里),隨機選一個消息加解密密鑰,最后選擇一個比較簡單的消息加解密方式-明文方式。這時候,咱們的服務器就會與微信服務器之間有個橋梁了,用戶的關注,取關,按鈕等事件,發消息等都會從微信服務器發送到咱們服務器來,然后我們需要作出對應的返回,就可以抓取用戶的一些信息了。先上代碼。
/// <summary>
/// 微信消息回復類
/// </summary>
public class MessageHelper
{
/// <summary>
/// 返回消息模板
/// </summary>
private string Message_Text { get { return @"<xml>
<ToUserName><![CDATA[{0}]]></ToUserName>
<FromUserName><![CDATA[{1}]]></FromUserName>
<CreateTime>{2}</CreateTime>
<MsgType><![CDATA[text]]></MsgType>
<Content><![CDATA[{3}]]></Content>
</xml>"; } }
/// <summary>
/// 多客服回復消息
/// </summary>
private string Message_Customer { get { return @"<xml>
<ToUserName><![CDATA[{0}]]></ToUserName>
<FromUserName><![CDATA[{1}]]></FromUserName>
<CreateTime>{2}</CreateTime>
<MsgType><![CDATA[transfer_customer_service]]></MsgType>
</xml>"; } }
public string ResponseContent(string postStr)
{
XmlDocument xdoc = new XmlDocument();
xdoc.LoadXml(postStr);
var responseContent = "success";
XmlNode MsgType = xdoc.SelectSingleNode("/xml/MsgType");
if (MsgType != null)
{
switch (MsgType.InnerText)
{
case "event":
responseContent = EventHandle(xdoc);//事件處理
break;
case "text":
responseContent = TextHandle(xdoc);//接受文本消息處理
break;
default:
break;
}
}
return responseContent;
}
private string EventHandle(XmlDocument xdoc) //事件
{
var toUserName = xdoc.SelectNodes("/xml/ToUserName")[0].InnerText;//開發者微信公眾號
var openID = xdoc.SelectNodes("/xml/FromUserName")[0].InnerText;//微信用戶唯一ID
var eventType = xdoc.SelectNodes("/xml/Event")[0].InnerText;//事件
var eventKey = xdoc.SelectNodes("/xml/EventKey")[0].InnerText;//事件Key
var result = "";
switch (eventType)
{
case "subscribe"://關注事件
string welcomeContent = @"感謝您的關注!綁定xxx賬號立刻獲取現金!~~~ 如果您已經注冊過xxx,請點擊<a href='http://www.baidu.com'>快速綁定</a>;如果您還不是我們的會員請點擊<a href='http://www.baidu.com'>立即注冊</a>。";
result = string.Format(Message_Text, openID, toUserName, ConvertDateTimeInt(DateTime.Now).ToString(), welcomeContent);
break;
case "click"://自定義點擊事件
switch (eventKey)
{
case "LianXiKF":
if (DateTime.Now.Hour > 17 || DateTime.Now.Hour < 9)
{
string msg = "您好,感謝您的咨詢,人工客服工作時間為 09:00 至 18:00。";
result = string.Format(Message_Text, openID, toUserName, ConvertDateTimeInt(DateTime.Now), msg);
}
else {
result = string.Format(Message_Customer, openID, toUserName, ConvertDateTimeInt(DateTime.Now));
}
break;
default: break;
}
break;
default: break;
}
return result;
}
private string TextHandle(XmlDocument xdoc) //文本信息
{
var res = "success";
var content = xdoc.SelectNodes("/xml/Content")[0];
var toUserName = xdoc.SelectNodes("/xml/ToUserName")[0].InnerText;//開發者微信公眾號
var openID = xdoc.SelectNodes("/xml/FromUserName")[0].InnerText;//微信用戶唯一ID
if (content != null)
{
if (content.InnerText.Contains("您_好"))
{
res = string.Format(Message_Text, openID, toUserName, ConvertDateTimeInt(DateTime.Now), "嗨,您好!");
}
}
return res;
}
/// <summary>
/// 將時間轉化為Unix時間戳
/// </summary>
/// <param name="time"></param>
/// <returns></returns>
private int ConvertDateTimeInt(DateTime time)
{
DateTime startTime = TimeZone.CurrentTimeZone.ToLocalTime(new System.DateTime(1970, 1, 1));
return (int)(time - startTime).TotalSeconds;
}
}
這段代碼是樓主當初初識微信公眾所寫的代碼,里面只包含了關注、點擊事件,以及文本消息的自動回復等。但是微信里面還有好多事件,好多語音,圖片,視頻等消息的處理,咱們可以參考一下文檔:

所有的消息發送,事件都遵循着微信的流程圖:

以上是微信公眾號綁定咱們服務器之間的通信過程,接下來我會把我自己所用到的一些微信公眾號的知識來記錄下來以便以后少走點彎路。
