微信平臺接入web頁面功能接口 web
今年因工做須要,經過微信平臺接入公司的Wap頁面,回憶下,記錄內容,方面之後使用。json
1.成爲開發者後,你纔可使用公衆平臺的開發功能。須要填寫URL和ToKen,接口配置信息。api
2.服務器端開發以下接口,等待微信服務器調用。數組
URL:緩存
用來接收微信服務器數據的接口URL,安全
http://192.168.0.199/weixin/****.ashx(該地址不固定,能夠由後臺開發者根據實際狀況本身擬定,但只支持80端口)服務器
Token:微信
開發者能夠任意擬定,已備用做生成簽名(該Token會和接口URL中包含的Token進行比對,從而驗證安全性)。app
請求方式:ide
Get
接收參數:
參數 |
描述 |
signature |
微信加密簽名,signature結合了開發者填寫的token參數和請求中的timestamp參數、nonce參數。 |
timestamp |
時間戳 |
nonce |
隨機數 |
echostr |
隨機字符串 |
響應微信服務器:
開發者經過檢驗signature對請求進行校驗(下面有校驗方式)。若確認這次GET請求來自微信服務器,請原樣返回echostr參數內容,則接入生效,不然接入失敗。
加密/校驗流程以下:
1. 將token、timestamp、nonce三個參數進行字典序排序 2. 將三個參數字符串拼接成一個字符串進行sha1加密 3. 開發者得到加密後的字符串可與signature對比,標識該請求來源於微信 |
3. 在公衆平臺網站的高級功能 – 開發模式頁,點擊「成爲開發者」按鈕,填寫URL和Token。提交信息後,微信服務器將發送GET請求到填寫的URL上,進行接入驗證。
4.C#代碼
object signature = context.Request.QueryString["signature"]; object timestamp = context.Request.QueryString["timestamp"]; object nonce = context.Request.QueryString["nonce"]; object echoStr = context.Request.QueryString["echoStr"]; if (signature != null && signature.ToString() != "" && timestamp != null && timestamp.ToString() != "" && nonce != null && nonce.ToString() != "" && echoStr != null && echoStr.ToString() != "") { CheckSignature(signature.ToString(), timestamp.ToString(), nonce.ToString(), echoStr.ToString(), token); } /// <summary> /// 驗證微信 字典排序後 返回隨機數 /// </summary> /// 將token、timestamp、nonce三個參數進行字典排序 /// 將三個參數字符串拼接成一個字符串sha1加密 /// 獲取加密後的字符串可與signature 對比 若是爲true則返回隨數 /// <returns></returns> private void CheckSignature(string signature, string timestamp, string nonce, string echoStr, string Token) { string[] ArrTmp = { Token, timestamp, nonce }; Array.Sort(ArrTmp); //首º¡Á先¨¨字Á?典Ì?排?序¨° string tmpStr = string.Join("", ArrTmp); tmpStr = FormsAuthentication.HashPasswordForStoringInConfigFile(tmpStr, "SHA1"); //sha1 tmpStr = tmpStr.ToLower(); if (tmpStr == signature) { if (!string.IsNullOrEmpty(echoStr)) { System.Web.HttpContext.Current.Response.Write(echoStr); System.Web.HttpContext.Current.Response.End(); } } }
5.驗證經過後,就能夠獲得appid 和secret參數了
6.建立菜單
(1)目前自定義菜單最多包括3個一級菜單,每一個一級菜單最多包含5個二級菜單。一級菜單最多4個漢字,二級菜單最多7個漢字,多出來的部分將會以「...」代替。請注意,建立自定義菜單後,因爲微信客戶端緩存,須要24小時微信客戶端纔會展示出來。建議測試時能夠嘗試取消關注公衆帳號後再次關注,則能夠看到建立後的效果。
目前自定義菜單接口可實現兩種類型按鈕,以下:
click:
用戶點擊click類型按鈕後,微信服務器會經過消息接口推送消息類型爲event 的結構給開發者(參考消息接口指南),而且帶上按鈕中開發者填寫的key值,開發者能夠經過自定義的key值與用戶進行交互;
view:
用戶點擊view類型按鈕後,微信客戶端將會打開開發者在按鈕中填寫的url值 (即網頁連接),達到打開網頁的目的,建議與網頁受權獲取用戶基本信息接口結合,得到用戶的登入我的信息。
(2)示例:
接口調用請求說明
http請求方式:POST(請使用https協議)
https://api.weixin.qq.com/cgi-bin/menu/create?access_token=ACCESS_TOKEN
請求示例
{ "button":[ { "type":"click", "name":"今日歌曲", "key":"V1001_TODAY_MUSIC" }, { "type":"click", "name":"歌手簡介", "key":"V1001_TODAY_SINGER" }, { "name":"菜單", "sub_button":[ { "type":"view", "name":"搜索", "url":"http://www.soso.com/" }, { "type":"view", "name":"視頻", "url":"http://v.qq.com/" }, { "type":"click", "name":"贊一下咱們", "key":"V1001_GOOD" }] }] }
|
參數說明
參數 |
是否必須 |
說明 |
button |
是 |
一級菜單數組,個數應爲1~3個 |
sub_button |
否 |
二級菜單數組,個數應爲1~5個 |
type |
是 |
菜單的響應動做類型,目前有click、view兩種類型 |
name |
是 |
菜單標題,不超過16個字節,子菜單不超過40個字節 |
key |
click類型必須 |
菜單KEY值,用於消息接口推送,不超過128字節 |
url |
view類型必須 |
網頁連接,用戶點擊菜單可打開連接,不超過256字節 |
返回結果
正確時的返回JSON數據包以下:
{"errcode":0,"errmsg":"ok"}
錯誤時的返回JSON數據包以下(示例爲無效菜單名長度):
{"errcode":40018,"errmsg":"invalid button name size"}
(3)代碼
/// <summary> ///建立菜單 /// </summary> /// <param name=\"sender\"></param> /// <param name=\"e\"></param> protected void btnCreateMenu_Click(object sender, EventArgs e) { string postUrl = "https://api.weixin.qq.com/cgi-bin/menu/create?access_token={0}"; postUrl = string.Format(postUrl, GetAccessToken()); string menuInfo = getMenuInfo(); lblResult.Text = "結¨¢果?:êo" + PostWebRequest(postUrl, menuInfo); } /// <summary> /// 獲取微信 access_token /// </summary> /// <returns></returns> protected string GetAccessToken() { string accessToken = string.Empty; string getUrl = "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid={0}&secret={1}"; getUrl = string.Format(getUrl, "你的appid", "你的secret"); Uri uri = new Uri(getUrl); HttpWebRequest webReq = (HttpWebRequest)WebRequest.Create(uri); webReq.Method = "POST"; //獲取返回信息 HttpWebResponse response = (HttpWebResponse)webReq.GetResponse(); StreamReader streamReader = new StreamReader(response.GetResponseStream(), Encoding.Default); string returnJason = streamReader.ReadToEnd(); JavaScriptSerializer serializer = new JavaScriptSerializer(); Dictionary<string, object> json = (Dictionary<string, object>)serializer.DeserializeObject(returnJason); object value; if (json.TryGetValue("access_token", out value)) { accessToken = value.ToString(); } return accessToken; } /// <summary> ///菜單內容 /// </summary> /// <returns></returns> private string getMenuInfo() { //現暫時寫死 string menu = "{" + "\"button\":[" + "{" + "\"name\":\"服務\"," + "\"sub_button\":[" + "{" + "\"type\":\"view\"," + "\"name\":\"更多服務\"," + "\"url\":\"https://open.weixin.qq.com/connect/oauth2/authorize?appid= appid&redirect_uri=http://192.168.0.199/weixin/WeixinCommon.ashx?action=6&response_type=code&scope=snsapi_base&state=6#wechat_redirect\"" + "}," + "{" + "\"type\":\"view\"," + "\"name\":\"更多服務1\"," + "\"url\":\"https://open.weixin.qq.com/connect/oauth2/authorize?appid=appid&redirect_uri=http://192.168.0.199/weixin/WeixinCommon.ashx?action=10&response_type=code&scope=snsapi_base&state=10#wechat_redirect\"" + "}," + "{" + "\"type\":\"view\"," + "\"name\":\" 更多服務2\"," + "\"url\":\"https://open.weixin.qq.com/connect/oauth2/authorize?appid=appid&redirect_uri=http://192.168.0.199/weixin/WeixinCommon.ashx?action=11&response_type=code&scope=snsapi_base&state=11#wechat_redirect\"" + "}," + "{" + "\"type\":\"view\"," + "\"name\":\"更多服務3\"," + "\"url\":\"https://open.weixin.qq.com/connect/oauth2/authorize?appid=appid&redirect_uri=http://192.168.0.199/weixin/WeixinCommon.ashx?action=6&response_type=code&scope=snsapi_base&state=6#wechat_redirect\"" + "}," + "{" + "\"type\":\"view\"," + "\"name\":\"更多服務4 \"," + "\"url\":\"https://open.weixin.qq.com/connect/oauth2/authorize?appid=appid&redirect_uri=http://192.168.0.199/weixin/WeixinCommon.ashx?action=6&response_type=code&scope=snsapi_base&state=6#wechat_redirect\"" + "}]}," + "{" + "\"name\":\"業務\"," + "\"sub_button\":[" + "{" + "\"type\":\"view\"," + "\"name\":\"業務1\"," + "\"url\":\"https://open.weixin.qq.com/connect/oauth2/authorize?appid=appid&redirect_uri=http://192.168.0.199/weixin/WeixinCommon.ashx?action=5&response_type=code&scope=snsapi_base&state=5#wechat_redirect\"" + "}," + "{" + "\"type\":\"view\"," + "\"name\":\"業務2\"," + "\"url\":\"https://open.weixin.qq.com/connect/oauth2/authorize?appid=appid&redirect_uri=http://192.168.0.199/weixin/WeixinCommon.ashx?action=6&response_type=code&scope=snsapi_base&state=6#wechat_redirect\"" + "}," + "{" + "\"type\":\"view\"," + "\"name\":\"業務3\"," + "\"url\":\"https://open.weixin.qq.com/connect/oauth2/authorize?appid=appid&redirect_uri=http://192.168.0.199/weixin/WeixinCommon.ashx?action=7&response_type=code&scope=snsapi_base&state=7#wechat_redirect\"" + "}," + "{" + "\"type\":\"view\"," + "\"name\":\"業務4\"," + "\"url\":\"https://open.weixin.qq.com/connect/oauth2/authorize?appid=appid&redirect_uri=http://192.168.0.199/weixin/WeixinCommon.ashx?action=8&response_type=code&scope=snsapi_base&state=8#wechat_redirect\"" + "}]" + "}," + "{" + "\"name\":\"辦理\"," + "\"sub_button\":[" + "{" + "\"type\":\"view\"," + "\"name\":\"辦理1 \"," + "\"url\":\"https://open.weixin.qq.com/connect/oauth2/authorize?appid=appid&redirect_uri=http://192.168.0.199/weixin/WeixinCommon.ashx?action=14&response_type=code&scope=snsapi_base&state=14#wechat_redirect\"" + "}," + "{"+ "\"type\":\"view\","+ "\"name\":\"辦理2\","+ "\"url\":\"https://open.weixin.qq.com/connect/oauth2/authorize?appid=appid&redirect_uri=http://192.168.0.199/weixin/WeixinCommon.ashx?action=1&response_type=code&scope=snsapi_base&state=1#wechat_redirect\"" + "},"+ "{"+ "\"type\":\"view\","+ "\"name\":\"辦理3\","+ "\"url\":\"https://open.weixin.qq.com/connect/oauth2/authorize?appid=appid&redirect_uri=http://192.168.0.199/weixin/WeixinCommon.ashx?action=2&response_type=code&scope=snsapi_base&state=2#wechat_redirect\"" + "},"+ "{"+ "\"type\":\"view\","+ "\"name\":\"辦理4\","+ "\"url\":\"https://open.weixin.qq.com/connect/oauth2/authorize?appid=appid&redirect_uri=http://192.168.0.199/weixin/WeixinCommon.ashx?action=3&response_type=code&scope=snsapi_base&state=3#wechat_redirect\"" + "},"+ "{"+ "\"type\":\"view\","+ "\"name\":\"辦理5\","+ "\"url\":\"https://open.weixin.qq.com/connect/oauth2/authorize?appid=appid&redirect_uri=http://192.168.0.199/weixin/WeixinCommon.ashx?action=4&response_type=code&scope=snsapi_base&state=4#wechat_redirect\"" + "}]}]}"; return menu; } /// <summary> /// 寫入 /// </summary> /// <param name=\"postUrl\"></param> /// <param name=\"menuInfo\"></param> /// <returns></returns> private string PostWebRequest(string postUrl, string menuInfo) { string returnValue = string.Empty; try { byte[] byteData = Encoding.UTF8.GetBytes(menuInfo); Uri uri = new Uri(postUrl); HttpWebRequest webReq = (HttpWebRequest)WebRequest.Create(uri); webReq.Method = "POST"; webReq.ContentType = "application/x-www-form-urlencoded"; webReq.ContentLength = byteData.Length; //定義Stream信息 Stream stream = webReq.GetRequestStream(); stream.Write(byteData, 0, byteData.Length); stream.Close(); //獲取返回信息 HttpWebResponse response = (HttpWebResponse)webReq.GetResponse(); StreamReader streamReader = new StreamReader(response.GetResponseStream(), Encoding.Default); returnValue = streamReader.ReadToEnd(); //關閉 streamReader.Close(); response.Close(); stream.Close(); } catch (Exception ex) { lblResult.Text = ex.ToString(); } return returnValue; } /// <summary> ///刪除菜單 /// </summary> /// <param name=\"sender\"></param> /// <param name=\"e\"></param> protected void btnDeleteMenu_Click(object sender, EventArgs e) { string postUrl = "https://api.weixin.qq.com/cgi-bin/menu/delete?access_token={0}"; postUrl = string.Format(postUrl, GetAccessToken()); string menuInfo = getMenuInfo(); lblResult.Text = "結¨¢果?:êo" + PostWebRequest(postUrl, menuInfo); } Aspx視圖中 <asp:Button ID="btnCreateMenu" runat="server" Text="創ä¡ä建¡§菜?單Ì£¤" onclick="btnCreateMenu_Click" /> <asp:Button ID="btnDeleteMenu" runat="server" Text="刪¦?除y菜?單Ì£¤" onclick="btnDeleteMenu_Click" /> <asp:Label ID="lblResult" runat="server" Text="結¨¢果?"></asp:Label> </form>
7.接口邏輯操做 統一接口
(1)菜單也能夠爲:
"\"type\":\"click\"," +
"\"name\":\"快樂每一天\"," +
"\"key\":\"yc_jbcg\""+
以xml文本形式傳遞參數
(2)代碼
/// <summary> /// 微信統一接口 /// </summary> /// <param name="context"></param> //string postStr = ""; HttpContext context; public void ProcessRequest(HttpContext context) { string getStr = ""; //接收參數 this.context = context; Stream s = context.Request.InputStream; //獲取傳入的stream byte[] b = new byte[s.Length]; s.Read(b, 0, (int)s.Length); getStr = Encoding.UTF8.GetString(b); Common.Log.WriteLog("接口記錄每次微信請求信?息:" + getStr); if (!string.IsNullOrEmpty(getStr)) { responseMsg(getStr,context); } } public void responseMsg(string postStr,HttpContext context) { try { System.Xml.XmlDocument postObj = new System.Xml.XmlDocument(); postObj.LoadXml(postStr); //Common.Log.WriteLog("responseMsg:-------" + postStr); var FromUserNameList = postObj.GetElementsByTagName("FromUserName"); string FromUserName = string.Empty; for (int i = 0; i < FromUserNameList.Count; i++) { if (FromUserNameList[i].ChildNodes[0].NodeType == System.Xml.XmlNodeType.CDATA) { FromUserName = FromUserNameList[i].ChildNodes[0].Value; //Common.Log.WriteLog("FromUserName:-------" + FromUserName); } } var toUsernameList = postObj.GetElementsByTagName("ToUserName"); string ToUserName = string.Empty; for (int i = 0; i < toUsernameList.Count; i++) { if (toUsernameList[i].ChildNodes[0].NodeType == System.Xml.XmlNodeType.CDATA) { ToUserName = toUsernameList[i].ChildNodes[0].Value; //Common.Log.WriteLog("ToUserName:-------" + ToUserName); } } var toMsgTypeList = postObj.GetElementsByTagName("MsgType"); string toMsgType = string.Empty; for (int i = 0; i < toMsgTypeList.Count; i++) { if (toMsgTypeList[i].ChildNodes[0].NodeType == System.Xml.XmlNodeType.CDATA) { toMsgType = toMsgTypeList[i].ChildNodes[0].Value; //Common.Log.WriteLog("toMsgType:-------" + toMsgType); } } var keywordList = postObj.GetElementsByTagName("Content"); string Content = string.Empty; for (int i = 0; i < keywordList.Count; i++) { if (keywordList[i].ChildNodes[0].NodeType == System.Xml.XmlNodeType.CDATA) { Content = keywordList[i].ChildNodes[0].Value; } } var textpl = ""; if (toMsgType == "text") { var time = DateTime.Now; textpl = "<xml><ToUserName><![CDATA[" + FromUserName + "]]></ToUserName>" + "<FromUserName><![CDATA[" + ToUserName + "]]></FromUserName>" + "<CreateTime>" + ConvertDateTimeInt(DateTime.Now) + "</CreateTime><MsgType><![CDATA[text]]></MsgType>" + "<Content><![CDATA[您好,歡迎觀看]]></Content><FuncFlag>0</FuncFlag></xml>"; } else if (toMsgType == "event") { var toEventList = postObj.GetElementsByTagName("Event"); string toEvent = string.Empty; for (int i = 0; i < toEventList.Count; i++) { if (toEventList[i].ChildNodes[0].NodeType == System.Xml.XmlNodeType.CDATA) { toEvent = toEventList[i].ChildNodes[0].Value; //Common.Log.WriteLog("toEvent:-------" + toEvent); } } var toEventKeyList = postObj.GetElementsByTagName("EventKey"); string toEventKey = string.Empty; for (int i = 0; i < toEventKeyList.Count; i++) { if (toEventKeyList[i].ChildNodes[0].NodeType == System.Xml.XmlNodeType.CDATA) { toEventKey = toEventKeyList[i].ChildNodes[0].Value; //Common.Log.WriteLog("toEventKey:-------" + toEventKey); } } //只有兩個 暫時寫 if (toEvent.ToLower() == "click" && toEventKey.ToLower() == "yc_jbcg") { string ResultStr = JCBindCarownerId(FromUserName, context); var time = DateTime.Now; textpl = "<xml><ToUserName><![CDATA[" + FromUserName + "]]></ToUserName>" + "<FromUserName><![CDATA[" + ToUserName + "]]></FromUserName>" + "<CreateTime>" + ConvertDateTimeInt(DateTime.Now) + "</CreateTime><MsgType><![CDATA[text]]></MsgType>" + "<Content><![CDATA[" + ResultStr + "]]></Content><FuncFlag>0</FuncFlag></xml>"; } if (toEvent.ToLower() == "click" && toEventKey.ToLower() == "yc_pm") { string Scontent="歡迎光臨,請登陸MyTaobao查看"; textpl = "<xml><ToUserName><![CDATA[" + FromUserName + "]]></ToUserName>" + "<FromUserName><![CDATA[" + ToUserName + "]]></FromUserName>" + "<CreateTime>" + ConvertDateTimeInt(DateTime.Now) + "</CreateTime><MsgType><![CDATA[text]]></MsgType>" + "<Content><![CDATA[" + Scontent + "]]></Content><FuncFlag>0</FuncFlag></xml>"; } if (toEvent.ToLower() == "subscribe") { var time = DateTime.Now; textpl = "<xml><ToUserName><![CDATA[" + FromUserName + "]]></ToUserName>" + "<FromUserName><![CDATA[" + ToUserName + "]]></FromUserName>" + "<CreateTime>" + ConvertDateTimeInt(DateTime.Now) + "</CreateTime><MsgType><![CDATA[text]]></MsgType>" + "<Content><![CDATA[您好?感D謝關注官方微信]]></Content><FuncFlag>0</FuncFlag></xml> "; } else if (toEvent.ToLower() == "unsubscribe") { } } //Common.Log.WriteLog("textpl:-------" + textpl); System.Web.HttpContext.Current.Response.Write(textpl); } catch (Exception ex) { Common.Log.WriteLog("微信統一接口錯誤信息:" + ex.Message); } } private int ConvertDateTimeInt(System.DateTime time) { System.DateTime startTime = TimeZone.CurrentTimeZone.ToLocalTime(new System.DateTime(1970, 1, 1)); return (int)(time - startTime).TotalSeconds; }
8.Get請求
(1)接收信息 獲取用戶惟一openid
/// <summary> /// 微信統一接口 /// </summary> /// <param name="context"></param> public void ProcessRequest(HttpContext context) { #region 保存每次微信請求信息 Uri Url = context.Request.Url; //獲取url鏈接 Common.Log.WriteLog("WeixinCommon接口記錄每次微信請求具體信息:" + Url); #endregion object action = context.Request.QueryString["action"]; //action 區分用戶點擊的內容 object code = context.Request.QueryString["code"]; //code string appid = ConfigurationManager.AppSettings["appid"]; //appid string secret = ConfigurationManager.AppSettings["secret"]; //secret if (action != null && action.ToString() != "" && code != null && code.ToString() != "") { StringBuilder postUrl = new StringBuilder(); postUrl.AppendFormat("https://api.weixin.qq.com/sns/oauth2/access_token?appid={0}&secret={1}&code={2}&grant_type=authorization_code", appid, secret, code); string openid = PostWebRequest(postUrl.ToString()); //Common.Log.WriteLog("openid Common頁°3面?:êo" + openid); PostWebPageByopenId(Convert.ToInt32(action), openid, context); } else { action = action==null ? "null" : action; code = code == null ? "null" : code; Common.Log.WriteLog("action==" + (string.IsNullOrEmpty(action.ToString())? "null" : action) + "\\code=" +( string.IsNullOrEmpty(code.ToString())? "null" : code)); } } /// <summary> /// 根據url請求openid /// </summary> /// <param name=\"postUrl\"></param> /// <param name=\"menuInfo\"></param> /// <returns></returns> private string PostWebRequest(string postUrl) { string returnValue = string.Empty; try { Uri uri = new Uri(postUrl); HttpWebRequest webReq = (HttpWebRequest)WebRequest.Create(uri); webReq.Method = "POST"; webReq.ContentType = "application/x-www-form-urlencoded"; //獲取返回信息 HttpWebResponse response = (HttpWebResponse)webReq.GetResponse(); StreamReader streamReader = new StreamReader(response.GetResponseStream(), Encoding.Default); returnValue = streamReader.ReadToEnd(); JavaScriptSerializer serializer = new JavaScriptSerializer(); Dictionary<string, object> json = (Dictionary<string, object>)serializer.DeserializeObject(returnValue); object value; if (json.TryGetValue("openid", out value)) { returnValue = value.ToString(); } if (returnValue.Contains("errcode")) returnValue = ""; return returnValue; } catch (Exception ex) { Common.Log.WriteLog("微信返回內容信息" + ex); } return returnValue; }
(2)業務處理
/// <summary> /// 根據條件,判斷用戶選擇的頁面 /// </summary> /// <param name="action">頁面參數</param> private void PostWebPageByopenId(int action,string openid,HttpContext context) { string strwhere = " openid='" + openid + "'"; BLL.WeiXin wxbll = new BLL.WeiXin(); IList< Model.WeiXin> wxList = wxbll.GetModelList(strwhere); if (wxList.Count > 0) { try { context.Session["openid"] = wxList[0].OpenID; Model.TemUser Usermodel = new BLL.TemUser().GetUser(Convert.ToInt32(wxList[0].Userid)); context.Session["CarUser"] = Usermodel; context.Session["UserLogin"] = true; } catch (Exception ex) { Common.Log.WriteLog("微信接口錯誤信息" + ex.Message); } } else { context.Response.Redirect("/Login.aspx?openid=" + openid); return; } // } switch (action) { case 1: context.Response.Redirect("/myFuWu.aspx"); break; case 2: context.Response.Redirect("/myYeWu.aspx"); break; default: context.Response.Redirect("/Login.aspx?openid=" + openid); break; } }
(3)頁面作相應功能處理 大概功能流程以下圖