开发的公众号需要是 服务号,现在好像一定是服务器,还需要交300块钱做微信认证,认证通过就可以开发了,如下图进入公众号后面的截图查看,
步骤:
1、--不能使用固定IP地址
2、--接口开发使用固定端口80,(指外网端口一定是80)
3、--ISP服务商一般会把80端口屏蔽住的,我们则可以向他们申请备案开通,也可以使用NAT123跳过屏蔽。首先我们对URL端口检测否则开通,打开网址(用域名或者固定IP地址检试都可以)
打开端口测试URL: http://tool.chinaz.com/port/
遇到这种情况解方法是,1、为了稳定,可以向ISP服务器申请备案开通,
如果这个端口没被封的话我们还要做路由器的端口映谢,例如
遇到这种情况解方法是,2、--用Nat123跳过ISP屏蔽(需要充值30元,相当于收费了,我充了30元)
--注册账号:fel***ng 密码:fe***511
--到Nat123官网下载一个客户端程序:http://www.nat123.com/ 按要求设置好如下图
映谢成功我们去检测下端口情况,如下图(Nat123还给了一个免费的域名我们),端口通了
还可以用当然我感觉不是很稳定,主要是感觉有点延迟的,
啰嗦下(一般在开发项目的时候都配置了好),IIS的映谢端口如下图所示!
-------------------------------------------------------------------------------------------------------------------------
前提做了我们现在入正题了,
我们在本地服务器上开发好源码,例如如下源码,注意微信公众号GET数据和POST数据,我们要分析他的异常的,做好日志
using System.Configuration;//哈希算法命名引用
public partial class WXDefault2 : System.Web.UI.Page
{
/// <summary>
/// 微信的Token
/// </summary>
const string Token = "ysjakieTok";
protected void Page_Load(object sender, EventArgs e)
{
string postStr = "";
//配置信息,只有在微信做提交配置的时候才会执行。
Valid();
if (Request.HttpMethod.ToLower() == "post")
{
postStr = PostInput();
if (false == string.IsNullOrEmpty(postStr))
{
//信息返回
ResponseMsg(postStr);
}
}
}
/// <summary>
/// 返回信息结果(微信信息返回)
/// </summary>
/// <param name="weixinXML"></param>
private void ResponseMsg(string weixinXML)
{
//回复消息的部分:你的代码写在这里
//根据关键词 自定义回复
string ToUserName = "";
string FromUserName = "";
string CreateTime = "";
string Content = "";
try
{
WriteLog(weixinXML);
var xDoc = XDocument.Parse(weixinXML);
var q = (from c in xDoc.Elements() select c).ToList();
var msgType = q.Elements("MsgType").First().Value; // 获取信息内容的类型
#region
//按钮事件
if (0 == string.Compare("event", msgType, true))
{
ToUserName = q.Elements("ToUserName").First().Value;//开发者微信号
FromUserName = q.Elements("FromUserName").First().Value;//发送方帐号(一个OpenID)
#region 事件
string strEvent = "";
string strEventKey = "";
strEvent = q.Elements("Event").First().Value;
CreateTime = q.Elements("CreateTime").First().Value;
//单击事件
if (strEvent.ToLower() == "click")
{
//图文推送
strEventKey = q.Elements("EventKey").First().Value;
}
//关注公众号
else if (strEvent.ToLower() == "subscribe")
{
strEventKey = q.Elements("EventKey").First().Value;
//未关注扫描带参数的二维码
if (strEventKey.Contains("qrscene_"))
{
string vaule = strEventKey.Replace("qrscene_", "");
}
}
//已关注扫描带参数的二维码
else if (strEvent.ToLower() == "scan")
{
strEventKey = q.Elements("EventKey").First().Value;
}
#endregion
}
#endregion
//用户文本信息
else if (0 == string.Compare("text", msgType, true))
{
ToUserName = q.Elements("ToUserName").First().Value;//开发者微信号
FromUserName = q.Elements("FromUserName").First().Value;//发送方帐号(一个OpenID)
Content = q.Elements("Content").First().Value;//发送方帐号(一个OpenID)
SendWx(FromUserName, ToUserName, "公众号反馈:"+Content); //调用返回信息,这里我们可以从数据库里返回在查询,像12306公众号一样
}
}
catch (Exception ex)
{
WriteLog(ex.ToString());
}
Response.End();
}
/// <summary>
/// 图片消息
/// </summary>
/// <param name="ToUsername"></param>
/// <param name="FromUserName"></param>
/// <returns></returns>
public static bool SendWxPic(string ToUsername, string FromUserName, string MediaId)
{
var textTpl = "<xml>"
+ "<ToUserName><![CDATA[{0}]]></ToUserName>"
+ "<FromUserName><![CDATA[{1}]]></FromUserName>"
+ "<CreateTime>{2}</CreateTime>"
+ "<MsgType><![CDATA[image]]></MsgType>"
+ "<Image>"
+ "<MediaId><![CDATA[{3}]]></MediaId>"
+ "</Image>"
+ "</xml>";
HttpResponse resp = System.Web.HttpContext.Current.Response;
resp.Write(string.Format(textTpl, FromUserName, ToUsername, ConvertDateTimeInt(DateTime.Now), MediaId));
return true;
}
/// <summary>
/// 消息转发到客服
/// </summary>
/// <param name="ToUsername"></param>
/// <param name="FromUserName"></param>
/// <returns></returns>
public static bool SendWx(string ToUsername, string FromUserName)
{
var textTpl = "<xml>"
+ "<ToUserName><![CDATA[{0}]]></ToUserName>"
+ "<FromUserName><![CDATA[{1}]]></FromUserName>"
+ "<CreateTime>{2}</CreateTime>"
+ "<MsgType><![CDATA[transfer_customer_service]]></MsgType>"
+ "</xml>";
HttpResponse resp = System.Web.HttpContext.Current.Response;
resp.Write(string.Format(textTpl, FromUserName, ToUsername, ConvertDateTimeInt(DateTime.Now)));
return true;
}
/// <summary>
/// 回复文本消息
/// </summary>
/// <param name="ToUsername"></param>
/// <param name="FromUserName"></param>
/// <param name="_tmpContent"></param>
/// <returns></returns>
public static void SendWx(string ToUsername, string FromUserName, string _tmpContent)
{
var textTpl = "<xml>"
+ "<ToUserName><![CDATA[{0}]]></ToUserName>"
+ "<FromUserName><![CDATA[{1}]]></FromUserName>"
+ "<CreateTime>{2}</CreateTime>"
+ "<MsgType><![CDATA[{3}]]></MsgType>"
+ "<Content><![CDATA[{4}]]></Content>"
+ "</xml>";
HttpResponse resp = System.Web.HttpContext.Current.Response;
resp.Write(string.Format(textTpl,ToUsername,FromUserName,ConvertDateTimeInt(DateTime.Now), "text", _tmpContent));
}
/// <summary>
/// 检验signature
/// </summary>
private void Valid()
{
WriteLog("日志记下公众号GET信息方便查异常:" + Request.QueryString.ToString());
//微信服务器配置提交时,echoStr才不为空。
string echoStr = Request.QueryString["echoStr"];
if (echoStr != null)
{
if (CheckSignature())
{
if (!string.IsNullOrEmpty(echoStr))
{
Response.Write(echoStr); Response.End();//回复响应微信
}
}
}
}
/// <summary>
/// 验证微信签名OK
/// </summary>
/// * 将token、timestamp、nonce三个参数进行字典序排序
/// * 将三个参数字符串拼接成一个字符串进行sha1加密
/// * 开发者获得加密后的字符串可与signature对比,标识该请求来源于微信。
/// <returns></returns>
private bool CheckSignature()
{
string signature = Request.QueryString["signature"].ToString();
string timestamp = Request.QueryString["timestamp"].ToString();
string nonce = Request.QueryString["nonce"].ToString();
//token
string[] ArrTmp = { Token, timestamp, nonce };
Array.Sort(ArrTmp); //字典排序
string tmpStr = string.Join("", ArrTmp);
SHA1 sha1 = new SHA1CryptoServiceProvider();//定义哈希算法对象
byte[] bytResult = sha1.ComputeHash(System.Text.Encoding.Default.GetBytes(tmpStr));//strSource为传入的字符串,字节数组为加密后的
tmpStr = BitConverter.ToString(bytResult);//转换成相同字符类型
tmpStr = tmpStr.ToLower().Replace("-","");//转换成小写
if (tmpStr == signature)
{
return true;
}
else
{
return false;
}
}
/// <summary>
/// 获取POST返回来的数据
/// </summary>
/// <returns></returns>
private string PostInput()
{
try
{
System.IO.Stream s = Request.InputStream;
int count = 0;
byte[] buffer = new byte[s.Length];
StringBuilder builder = new StringBuilder();
while ((count = s.Read(buffer, 0, buffer.Length)) > 0)
{
builder.Append(Request.ContentEncoding.GetString(buffer, 0, count));
}
s.Flush();
s.Close();
s.Dispose();
return builder.ToString();
}
catch (Exception ex)
{ throw ex; }
}
/// <summary>
/// unix时间转换为datetime
/// </summary>
/// <param name="timeStamp"></param>
/// <returns></returns>
private DateTime UnixTimeToTime(string timeStamp)
{
DateTime dtStart = TimeZone.CurrentTimeZone.ToLocalTime(new DateTime(1970, 1, 1));
long lTime = long.Parse(timeStamp + "0000000");
TimeSpan toNow = new TimeSpan(lTime);
return dtStart.Add(toNow);
}
/// <summary>
/// datetime转换为unixtime
/// </summary>
/// <param name="time"></param>
/// <returns></returns>
public static int ConvertDateTimeInt(System.DateTime time)
{
System.DateTime startTime = TimeZone.CurrentTimeZone.ToLocalTime(new System.DateTime(1970, 1, 1));
return (int)(time - startTime).TotalSeconds;
}
/// <summary>
/// 写日志(用于跟踪)
/// </summary>
private void WriteLog(string strMemo)
{
string filename = Server.MapPath("~/logs/log.txt");
if (!Directory.Exists(Server.MapPath("//logs//")))
Directory.CreateDirectory(Server.MapPath("//logs//"));
StreamWriter sr = null;
try
{
if (!File.Exists(filename))
{
sr = File.CreateText(filename);
}
else
{
sr = File.AppendText(filename);
}
sr.WriteLine(strMemo);
}
catch
{
}
finally
{
if (sr != null)
sr.Close();
}
}
在本地打开我们的项目看看有没有异常,如果没有我们则,开始到 公众号后台进行测试了,
公众号后台---开发--基础设置--修改配置---按要求填写完成
服务器地址(URL)-->是我们刚才在本地开发的URL地址 如:http://220***.nat123.cc/WXDefault2.aspx
Token--->是令牌 是和我们本地定义的令牌 字符串是一致的,如我的:ysjakieTok
EncodingAESKey-->消息加解密密钥 随机生成,在本地开发时用来加密码解密的
点击保存后,到界基础设置里,要把 配置开启,
公众号后台---开发--开发都工具--里面都是一些开发说明文档 以及 开发接口的测试工具,很不错的
我们这里点,在线端口调试工具,
里面的测试填法,按对应要求填写即可如下图
返回信息如下图,说明成功了,
我到公众号上,测试看看,
测试成功了,
END!!