1、首先了解本文要解決的問題:javascript
公司前一段開發了移動網站,老闆喜歡經過微信看,而後把看到的東西經過右上角的按鈕分享出來,但老闆發現分享出來的東西,沒有指定的圖片,沒有描述;因此我就得老老實實幹活了。。。php
以下圖所示:html
點擊發送給朋友,或者分享到朋友圈時,須要帶上老闆指定的圖片、描述和標題。前端
2、嘗試解決問題java
剛開始,經過網上查閱,發現微信會自動抓取頁面的title屬性做爲標題,和頁面中第一張尺寸大於等於300*300的圖片,做爲分享出來的圖片,因而帶着偷懶的想法先這樣嘗試了一下,會有一下幾個問題:node
①不能自定義描述信息python
②當頁面內沒有超過300*300的圖片時,就不能顯示圖片了,因而我放了一張300*300的公司的logo在每一個頁面內,首先老闆並不喜歡,其次會影響加載速度,同時當用戶在隱藏圖片還沒加載出來的時候就進行分享動做,那麼圖片仍是識別不出來。。。jquery
改完第一次,用了一段時間,老闆不滿意,要求繼續優化,因而第二版開始更新。。web
既然不能走野路子,只能經過微信給出的開發文檔進行更改了。。請參考官網文檔:http://mp.weixin.qq.com/wiki/7/1c97470084b73f8e224fe6d9bab1625b.htmlajax
微信發佈了《微信JS-SDK說明文檔》供開發者使用,而且給出了示例,包含了php、java、nodejs、python示例,然而並無什麼卵用!由於我是一個.net開發!!!
只能本身動手,豐衣足食了。
3、說幹就幹
代碼分兩個部分,js和後端;後端咱們目前使用的是webservice,其中用到了Cache,下面貼主要代碼了
①接口中代碼,須要解決js跨域問題
1 [WebMethod(Description = "微信分享請求參數接口")] 2 [ScriptMethod(UseHttpGet = false)] 3 public string GetWXSharedParam(string url) 4 { 5 string timestamp = Common.APPApplyClass.WxSharedClass.ConvertDateTimeInt(DateTime.Now).ToString(); 6 string nonceStr = Guid.NewGuid().ToString(); 7 string ticket = string.Empty; 8 string appId = ConfigurationManager.AppSettings["appid"]; 9 10 //獲取jsapi_ticket 11 if (HttpRuntime.Cache["JsApiTicket"] == null) 12 { 13 Common.APPApplyClass.WxSharedClass.GetJsApiTicket(); 14 } 15 ticket = HttpRuntime.Cache["JsApiTicket"] as string; 16 if (string.IsNullOrEmpty(ticket)) 17 { 18 return JsonConvert.SerializeObject(new { result = false }); 19 } 20 21 SortedList<string, string> SLString = new SortedList<string, string>(); 22 SLString.Add("noncestr", nonceStr); 23 SLString.Add("url", url); 24 SLString.Add("timestamp", timestamp); 25 SLString.Add("jsapi_ticket", ticket); 26 27 StringBuilder sb = new StringBuilder(); 28 foreach (KeyValuePair<string, string> des in SLString) //返回的是KeyValuePair,在學習的時候儘可能少用var,起碼要知道返回的是什麼 29 { 30 sb.Append(des.Key + "=" + des.Value + "&"); 31 } 32 string signature = sb.ToString().Substring(0, sb.ToString().Length - 1); 33 signature = FormsAuthentication.HashPasswordForStoringInConfigFile(signature, "SHA1").ToLower(); 34 35 return JsonConvert.SerializeObject(new { result = true, timestamp, nonceStr, signature, appId }); 36 }
②新建了一個類,提供了上個方法中須要調用的方法和實體
1 public static class WxSharedClass 2 { 3 static System.Web.Caching.Cache objCache = HttpRuntime.Cache; 4 5 /// <summary> 6 /// 獲取jsapi_ticket 7 /// 有效期7200秒,開發者必須在本身的服務全局緩存jsapi_ticket 8 /// </summary> 9 /// <returns></returns> 10 public static void GetJsApiTicket() 11 { 12 string accessToken = string.Empty; 13 if (objCache["AccessToken"] == null) 14 { 15 GetAccessToken(); 16 } 17 accessToken = objCache["AccessToken"] as string; 18 if (!string.IsNullOrEmpty(accessToken)) 19 { 20 accessToken = objCache["AccessToken"] as string; 21 string url = "https://api.weixin.qq.com/cgi-bin/ticket/getticket?access_token=" + accessToken + "&type=jsapi"; 22 string resStr = HttpGet(url); 23 TicketModel model = JsonConvert.DeserializeObject<TicketModel>(resStr); 24 if (!string.IsNullOrEmpty(model.ticket)) 25 { 26 //請求成功了 27 DateTime dt = DateTime.Now.AddSeconds(Convert.ToInt32(model.expires_in)); 28 objCache.Insert("JsApiTicket", model.ticket, null, dt, System.Web.Caching.Cache.NoSlidingExpiration); 29 } 30 } 31 } 32 33 /// <summary> 34 /// DateTime時間格式轉換爲Unix時間戳格式 35 /// </summary> 36 /// <param name="time"> DateTime時間格式</param> 37 /// <returns>Unix時間戳格式</returns> 38 public static int ConvertDateTimeInt(System.DateTime time) 39 { 40 System.DateTime startTime = TimeZone.CurrentTimeZone.ToLocalTime(new System.DateTime(1970, 1, 1)); 41 return (int)(time - startTime).TotalSeconds; 42 } 43 44 /// <summary> 45 /// 獲取access_token 46 /// 有效期7200秒,開發者必須在本身的服務全局緩存access_token 47 /// </summary> 48 /// <returns></returns> 49 private static void GetAccessToken() 50 { 51 string appId = ConfigurationManager.AppSettings["appid"];//訂閱號應用id 52 string secret = ConfigurationManager.AppSettings["secret"];//訂閱號應用密鑰 53 string url = 54 "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=" + appId + "&secret=" + secret; 55 string resStr = HttpGet(url); 56 if (!resStr.Contains("errcode"))//string.IsNullOrEmpty(model.errcode) 57 { 58 //請求成功了 59 AccessTokenModel model = JsonConvert.DeserializeObject<AccessTokenModel>(resStr); 60 DateTime dt = DateTime.Now.AddSeconds(Convert.ToInt32(model.expires_in)); 61 objCache.Insert("AccessToken", model.access_token, null, dt, System.Web.Caching.Cache.NoSlidingExpiration); 62 } 63 } 64 65 66 /// <summary> 67 /// HttpGet請求 68 /// </summary> 69 /// <param name="url"></param> 70 /// <returns></returns> 71 private static string HttpGet(string url) 72 { 73 HttpWebRequest request = (HttpWebRequest)WebRequest.Create(url); 74 request.Method = "GET"; 75 request.ContentType = "text/html;charset=UTF-8"; 76 HttpWebResponse response = (HttpWebResponse)request.GetResponse(); 77 Stream myResponseStream = response.GetResponseStream(); 78 StreamReader myStreamReader = new StreamReader(myResponseStream, Encoding.GetEncoding("utf-8")); 79 string retString = myStreamReader.ReadToEnd(); 80 myStreamReader.Close(); 81 myResponseStream.Close(); 82 return retString; 83 } 84 } 85 86 public class AccessTokenModel 87 { 88 public string access_token; 89 90 public string expires_in; 91 } 92 93 public class TicketModel 94 { 95 public string errcode; 96 97 public string errmsg; 98 99 public string ticket; 100 101 public string expires_in; 102 }
③js代碼
1 //引用jquery 2 <script type="text/javascript" src="js/jquery.js"></script> 3 <script type="text/javascript" src="http://res.wx.qq.com/open/js/jweixin-1.0.0.js"></script> 4 <script type="text/javascript"> 5 var title = '測試標題', 6 imgUrl = '圖片地址', 7 desc = '測試描述'; 8 9 $(function () { 10 /* 11 wx.checkJsApi({ 12 jsApiList: [ 13 'onMenuShareTimeline', 14 'onMenuShareAppMessage' 15 ], // 須要檢測的JS接口列表,全部JS接口列表見附錄2, 16 success: function (res) { 17 allPrpos(res); 18 // 以鍵值對的形式返回,可用的api值true,不可用爲false 19 // 如:{"checkResult":{"chooseImage":true},"errMsg":"checkJsApi:ok"} 20 } 21 }); 22 */ 23 24 var param = { 25 url: location.href.split('#')[0] 26 }; 27 //從後端請求參數 28 AjaxPostData("url", param, function (json) { 29 if (json.result === true) { 30 31 wx.config({ 32 debug: false, // 開啓調試模式,調用的全部api的返回值會在客戶端alert出來,若要查看傳入的參數,能夠在pc端打開,參數信息會經過log打出,僅在pc端時纔會打印。 33 appId: json.appId, // 必填,公衆號的惟一標識 34 timestamp: json.timestamp, // 必填,生成簽名的時間戳 35 nonceStr: json.nonceStr, // 必填,生成簽名的隨機串 36 signature: json.signature,// 必填,簽名,見附錄1 37 menuItem: 'addContact', 38 jsApiList: [ 39 'onMenuShareTimeline', 40 'onMenuShareAppMessage' 41 ] // 必填,須要使用的JS接口列表,全部JS接口列表見附錄2 42 }); 43 } 44 }); 45 }); 46 47 wx.ready(function () { 48 // config信息驗證後會執行ready方法,全部接口調用都必須在config接口得到結果以後,config是一個客戶端的異步操做,因此若是須要在頁面加載時就調用相關接口,則須把相關接口放在ready函數中調用來確保正確執行。對於用戶觸發時才調用的接口,則能夠直接調用,不須要放在ready函數中。 49 50 51 //獲取「分享到朋友圈」按鈕點擊狀態及自定義分享內容接口 52 wx.onMenuShareTimeline({ 53 title: title, // 分享標題 54 link: window.location.href, // 分享連接 55 imgUrl: imgUrl, // 分享圖標 56 trigger: function (res) { 57 //監聽Menu中的按鈕點擊時觸發的方法,該方法僅支持Menu中的相關接口。 58 //不要嘗試在trigger中使用ajax異步請求修改本次分享的內容,由於客戶端分享操做是一個同步操做,這時候使用ajax的回包會尚未返回。 59 }, 60 success: function (res) { 61 //接口調用成功時執行的回調函數。 62 }, 63 cancel: function (res) { 64 //用戶點擊取消時的回調函數,僅部分有用戶取消操做的api纔會用到。 65 }, 66 fail: function (res) { 67 //接口調用失敗時執行的回調函數。 68 }, 69 complete: function (res) { 70 //接口調用完成時執行的回調函數,不管成功或失敗都會執行。 71 } 72 //以上幾個函數都帶有一個參數,類型爲對象,其中除了每一個接口自己返回的數據以外,還有一個通用屬性errMsg,其值格式以下: 73 /*調用成功時:"xxx:ok" ,其中xxx爲調用的接口名 74 用戶取消時:"xxx:cancel",其中xxx爲調用的接口名 75 調用失敗時:其值爲具體錯誤信息 76 */ 77 }); 78 79 80 //獲取「分享給朋友」按鈕點擊狀態及自定義分享內容接口 81 wx.onMenuShareAppMessage({ 82 title: title, // 分享標題 83 desc: desc, // 分享描述 84 link: window.location.href, // 分享連接 85 imgUrl: imgUrl, // 分享圖標 86 type: 'link', // 分享類型,music、video或link,不填默認爲link 87 dataUrl: '', // 若是type是music或video,則要提供數據連接,默認爲空 88 success: function () { 89 // 用戶確認分享後執行的回調函數 90 }, 91 cancel: function () { 92 // 用戶取消分享後執行的回調函數 93 } 94 }); 95 }); 96 97 wx.error(function (res) { 98 //allPrpos(res); 99 // config信息驗證失敗會執行error函數,如簽名過時致使驗證失敗,具體錯誤信息能夠打開config的debug模式查看,也能夠在返回的res參數中查看,對於SPA能夠在這裏更新簽名。 100 101 }); 102 103 //這是我抄的咱們前端開發小組的,不知道他們抄的誰的。。。 104 var AjaxPostData = function(url, data, success) { 105 /// <summary> 106 /// Ajax的POST方法 107 /// </summary> 108 /// <param name="url" type="String"> 109 /// 網址/參數 110 /// </param> 111 /// <param name="data" type="JSON類型"> 112 /// 參數 113 /// </param> 114 /// <param name="success" type="Function"> 115 /// 回調函數,不用這個的時候爲同步,用的時候爲異步(有一個返回數據參數(數據)) 116 /// </param> 117 /// <returns type="string">同步時返回數據,異步時在回調函數中取</returns> 118 119 var val = ""; 120 121 var param = { 122 url: encodeURI(url), 123 type: "POST", 124 timeout: 50000, 125 async: false, 126 data: data, 127 dataType: "text", 128 success: function(tempData) {}, 129 error: function(XMLHttpRequest, textStatus, errorThrown) { 130 console.log(arguments); 131 } 132 }; 133 134 if (!success) { 135 param.async = false; 136 param.success = function(tempData) { 137 val = tempData; 138 }; 139 } else { 140 param.async = true; 141 param.success = function(r) { 142 if (success) { 143 // var result = $(r).find('string').html(); 144 // result = result.StringToJsonObject(); 145 146 var len = r.length; 147 var result = JSON.parse(r.substring(76, len - 9)); 148 149 success(result); 150 } 151 }; 152 } 153 154 $.ajax(param); 155 156 return val; 157 } 158 </script>