最近因为需要用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;
}
}
这段代码是楼主当初初识微信公众所写的代码,里面只包含了关注、点击事件,以及文本消息的自动回复等。但是微信里面还有好多事件,好多语音,图片,视频等消息的处理,咱们可以参考一下文档:
所有的消息发送,事件都遵循着微信的流程图:
以上是微信公众号绑定咱们服务器之间的通信过程,接下来我会把我自己所用到的一些微信公众号的知识来记录下来以便以后少走点弯路。