不少時候咱們要在微信中分享h5網頁,這個時候就得用微信的分享接口來自定義分享的地址、標題、描述、縮略圖了。javascript
分享到微信的時候遇到一個問題,就是第一次分享到微信裏,是正確的,可是在微信打開分享的連接,再次分享的時候,發現小圖片沒了。html
緣由就是微信在你分享的時候,會自動給你分享的地址後面加入參數,致使你分享的地址改變了,這時候再去用原來的地址獲取簽名,就不能用了。java
解決方法,動態獲取地址:jquery
var link = encodeURIComponent(location.href.split('#')[0]);//編碼動態獲取地址web
var link = location.href.split('#')[0];//動態獲取地址ajax
代碼:算法
<script src="js/jquery.min.js"></script> <script src="http://res.wx.qq.com/open/js/jweixin-1.2.0.js"></script> <script src="js/sha1.js"></script> <script src="js/WeiXinShare.js"></script> <script type="text/javascript"> //var link = "http://adv.xxx.com/Index.html";//原網頁地址 //var link = encodeURIComponent(location.href.split('#')[0]);//編碼動態獲取地址 //var link = "http://adv.xxx.com/Index.html?from=groupmessage";//微信加入參數後的地址 var link = location.href.split('#')[0];//動態獲取當前地址,防止微信在原地址後加入參數 var imgUrl = "http://adv.xxx.com/img/fm.png";//縮略圖地址 var apiUrl = "https://api.xxx.com/Common/GetSignature";//服務器端簽名 var title = "這裏是分享標題"; var desc = "這裏是分享描述"; Share(link, imgUrl, title, desc, apiUrl); </script>
Share函數代碼:json
function Share(link, imgUrl, title, desc, apiUrl) { var randNum = Math.floor(Math.random(1000, 9999) * 10000); $.ajax({ url: apiUrl, type: 'GET', dataType: 'jsonp', async: false, data: { linkUrl: link, randNum: randNum } }).done(function (d) { //debugger; ShareCallBack(d, link, imgUrl, title, desc); }).fail(function () { console.log("error"); }).always(function () { }); } function ShareCallBack(d, link, imgUrl, title, desc) { //debugger; var appid = ""; var timestamp = ""; var noncestr = ""; var signature = ""; if (d.Data != undefined && d.Data != null) { var result = $.parseJSON(d.Data); timestamp = result.timestamp; noncestr = result.noncestr; signature = result.signature; appid = result.appid; //weixin begin wx.config({ debug: false, // 開啓調試模式,調用的全部api的返回值會在客戶端alert出來,若要查看傳入的參數,能夠在pc端打開,參數信息會經過log打出,僅在pc端時纔會打印。 appId: appid, // 必填,公衆號的惟一標識 timestamp: timestamp, // 必填,生成簽名的時間戳 nonceStr: noncestr, // 必填,生成簽名的隨機串 signature: signature, // 必填,簽名,見附錄1 jsApiList: ["onMenuShareTimeline", "onMenuShareAppMessage", "onMenuShareQQ", "onMenuShareWeibo", "onMenuShareQZone"] //jsApiList 必填,須要使用的JS接口列表,全部JS接口列表見附錄2 }); wx.ready(function () { //獲取「分享到朋友圈」按鈕點擊狀態及自定義分享內容接口 // config信息驗證後會執行ready方法,全部接口調用都必須在config接口得到結果以後,config是一個客戶端的異步操做,因此若是須要在頁面加載時就調用相關接口,則須把相關接口放在ready函數中調用來確保正確執行。對於用戶觸發時才調用的接口,則能夠直接調用,不須要放在ready函數中。 wx.onMenuShareTimeline({ title: title, // 分享標題 desc: desc, // 分享描述 link: link, // 分享連接 imgUrl: imgUrl, // 分享圖標 success: function () { // 用戶確認分享後執行的回調函數 }, cancel: function () { // 用戶取消分享後執行的回調函數 } }); //獲取「分享給朋友」按鈕點擊狀態及自定義分享內容接口 wx.onMenuShareAppMessage({ title: title, // 分享標題 desc: desc, // 分享描述 link: link, // 分享連接 imgUrl: imgUrl, // 分享圖標 type: 'link', // 分享類型,music、video或link,不填默認爲link dataUrl: '', // 若是type是music或video,則要提供數據連接,默認爲空 success: function () { // 用戶確認分享後執行的回調函數 }, cancel: function () { // 用戶取消分享後執行的回調函數 } }); //獲取「分享到QQ」按鈕點擊狀態及自定義分享內容接口 wx.onMenuShareQQ({ title: title, // 分享標題 desc: desc, // 分享描述 link: link, // 分享連接 imgUrl: imgUrl, // 分享圖標 success: function () { // 用戶確認分享後執行的回調函數 }, cancel: function () { // 用戶取消分享後執行的回調函數 } }); //獲取「分享到騰訊微博」按鈕點擊狀態及自定義分享內容接口 wx.onMenuShareWeibo({ title: title, // 分享標題 desc: desc, // 分享描述 link: link, // 分享連接 imgUrl: imgUrl, // 分享圖標 success: function () { // 用戶確認分享後執行的回調函數 }, cancel: function () { // 用戶取消分享後執行的回調函數 } }); //獲取「分享到QQ空間」按鈕點擊狀態及自定義分享內容接口 wx.onMenuShareQZone({ title: title, // 分享標題 desc: desc, // 分享描述 link: link, // 分享連接 imgUrl: imgUrl, // 分享圖標 success: function () { // 用戶確認分享後執行的回調函數 }, cancel: function () { // 用戶取消分享後執行的回調函數 } }); wx.error(function (res) { // config信息驗證失敗會執行error函數,如簽名過時致使驗證失敗,具體錯誤信息能夠打開config的debug模式查看,也能夠在返回的res參數中查看,對於SPA能夠在這裏更新簽名。 }); }); //weixin end } }
服務器端簽名:api
/// <summary> /// 獲取微信 signature /// </summary> /// <param name="callback"></param> [AcceptVerbs("GET")] public void GetSignature(string callback, string linkUrl) { MessagesDataCodeModel json = new MessagesDataCodeModel(false, "無效參數", 401); try { string AppId = "xxxxxxxx";//微信公衆號官網簽發的 appid和appsecret string AppSecret = "xxxxxxx"; DateTime endDate = DateTime.Now.AddSeconds(7200); string token = "", ticket = ""; List<Models.WeiXinTokens> list = WeiXinTokensBLL.GetList(); if (list != null && list.Count > 0) { if (list[0].EndDate > DateTime.Now) { token = list[0].Token.Trim(); ticket = list[0].Ticket.Trim(); } } if (string.IsNullOrEmpty(token)) { string result = Common.WeiXinHelper.GetJsApiTicket(AppId, AppSecret); JavaScriptSerializer jss = new JavaScriptSerializer(); WeiXinTokenModel model = jss.Deserialize<WeiXinTokenModel>(result); if (model != null) { Models.WeiXinTokens wxt = new Models.WeiXinTokens(); wxt.Token = model.token; wxt.Ticket = model.ticket; wxt.EndDate = endDate; if (list.Count > 0) { wxt.ID = list[0].ID; WeiXinTokensBLL.ModifyEntity(wxt); } else { WeiXinTokensBLL.Append(wxt); } token = model.token; ticket = model.ticket; } } else { Models.WeiXinTokens wxt = list[0]; wxt.Token = token; wxt.Ticket = ticket; WeiXinTokensBLL.ModifyEntity(wxt); } string noncestr = Guid.NewGuid().ToString().Replace("-", ""); int timestamp = Utils.ConvertDateTimeInt(DateTime.Now); string key_str = "jsapi_ticket=" + ticket + "&noncestr=" + noncestr + "×tamp=" + timestamp + "&url=" + linkUrl; string signature = Utils.EncryptToSHA1(key_str); string jsonStr = "{\"ticket\":\"" + ticket + "\",\"token\":\"" + token + "\",\"noncestr\":\"" + noncestr + "\",\"timestamp\":\"" + timestamp + "\",\"appid\":\"" + AppId + "\",\"signature\":\"" + signature + "\",\"url\":\"" + linkUrl + "\"}"; json.Success = true; json.Msg = "操做成功"; json.Code = 200; json.Data = jsonStr; } catch (Exception ex) { json.Success = false; json.Msg = "服務器無響應"; json.Code = 500; json.Data = -1; } string str = ToJsonTran.ToJson2(json); if (!string.IsNullOrEmpty(callback)) { str = callback + "(" + str + ")"; } System.Web.HttpContext.Current.Response.Clear(); System.Web.HttpContext.Current.Response.Write(str); System.Web.HttpContext.Current.Response.End(); }
輔助方法:服務器
/// <summary> /// C# SHA1散列算法 /// </summary> /// <param name="str"></param> /// <returns></returns> public static string EncryptToSHA1(string str) { byte[] cleanBytes = Encoding.Default.GetBytes(str); byte[] hashedBytes = System.Security.Cryptography.SHA1.Create().ComputeHash(cleanBytes); return BitConverter.ToString(hashedBytes).Replace("-", ""); } /// <summary> /// DateTime時間格式轉換爲Unix時間戳格式 /// </summary> /// <param name="time"> DateTime時間格式</param> /// <returns>Unix時間戳格式</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; }
簽名程序:
using System; using System.Collections.Generic; using System.IO; using System.Linq; using System.Net; using System.Text; using System.Threading.Tasks; using System.Web.Script.Serialization; namespace Common { public class WeiXinHelper { public static string GetJsApiTicket(string AppId, string AppSecret) { JavaScriptSerializer jss = new JavaScriptSerializer(); string result_token = GetAccessToken(AppId, AppSecret); string result_jsapi_ticket = ""; if (!string.IsNullOrEmpty(result_token)) { result_jsapi_ticket = GetJsApiTicketByToken(result_token); } return "{\"token\":\"" + result_token + "\",\"ticket\":\"" + result_jsapi_ticket + "\"}"; } /// <summary> /// 得到微信AccessToken /// 正常返回:{"access_token":"ACCESS_TOKEN","expires_in":7200} /// 錯誤返回:{"errcode":40013,"errmsg":"invalid appid"} /// </summary> /// <param name="AppId"></param> /// <param name="AppSecret"></param> /// <returns></returns> public static string GetAccessToken(string AppId, string AppSecret) { string url = "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=" + AppId + "&secret=" + AppSecret; string result_token = ""; WebRequest webRequest = System.Net.HttpWebRequest.Create(url); WebResponse webResponse = webRequest.GetResponse(); Stream stream = webResponse.GetResponseStream(); using (StreamReader sr = new StreamReader(stream)) { result_token = sr.ReadToEnd(); } JavaScriptSerializer jss = new JavaScriptSerializer(); WeiXinAccessTokenResult atr = jss.Deserialize<WeiXinAccessTokenResult>(result_token); if (!string.IsNullOrEmpty(atr.access_token)) { return atr.access_token; } return ""; } public static string GetJsApiTicketByToken(string AccessToken) { string url = "https://api.weixin.qq.com/cgi-bin/ticket/getticket?access_token=" + AccessToken + "&type=jsapi"; string result = Utils.ClientRequest(url, "", "GET"); JavaScriptSerializer jss = new JavaScriptSerializer(); WeiXinJsApiTicketResult ticket_model = jss.Deserialize<WeiXinJsApiTicketResult>(result); if (ticket_model.errcode == "0") { return ticket_model.ticket; } return ""; } } public class WeiXinJsApiTicketResult { public string errcode { get; set; } public string errmsg { get; set; } public string ticket { get; set; } public string expires_in { get; set; } } public class WeiXinAccessTokenResult { //正常返回:{"access_token":"ACCESS_TOKEN","expires_in":7200} //錯誤返回:{"errcode":40013,"errmsg":"invalid appid"} public string access_token { get; set; } public string expires_in { get; set; } public string errcode { get; set; } public string errmsg { get; set; } public string error { get; set; } } }
微信分享SDK:https://mp.weixin.qq.com/wiki?t=resource/res_main&id=mp1421141115