寫在前面
前陣子因為有個項目需要做微信自定義分享功能,因而去研究了下微信JS-SDK相關知識。
此文做個簡單的記(tu)錄(cao)...
開始
所有的東西都從文檔開始:微信JSSDK說明文檔
項目需要用到的是分享接口 不過使用微信JS-SDK之前,需要做JS接口認證。
認證如下:
步驟一:綁定域名
步驟二:引入JS文件
步驟三:通過config接口注入權限驗證配置
步驟四:通過ready接口處理成功驗證
步驟五:通過error接口處理失敗驗證
具體解釋:
步驟一中允許使用域名/子域名,只要xx.com/xxx.txt或者xx.com/mp/xxx.txt能訪問就好。域名認證通過之后,此域名下的所有端口的網站都可以使用JS-SDK。
步驟二沒什么問題,略過。
步驟三最磨人,下面單獨講解。
config接口注入權限驗證配置
先來一段說明:
所有需要使用JS-SDK的頁面必須先注入配置信息,否則將無法調用(同一個url僅需調用一次,對于變化url的SPA的web app可在每次url變化時進行調用,目前Android微信客戶端不支持pushState的H5新特性,所以使用pushState來實現web app的頁面會導致簽名失敗,此問題會在Android6.2中修復)。
1
2
3
4
5
6
7
8
9
|
wx.config({ debug: true , // 開啟調試模式,調用的所有api的返回值會在客戶端alert出來, //若要查看傳入的參數,可以在pc端打開,參數信息會通過log打出,僅在pc端時才會打印。 appId: '' , // 必填,公眾號的唯一標識 timestamp: , // 必填,生成簽名的時間戳 nonceStr: '' , // 必填,生成簽名的隨機串 signature: '' , // 必填,簽名,見附錄1 jsApiList: [] // 必填,需要使用的JS接口列表,所有JS接口列表見附錄2 }); |
看到這里肯定懵逼了,這是都什么鬼...怎么玩啊。
提示我們去看附錄1...看完之后總結如下:
1.使用config接口注入權限驗證配置,重點是生成合法的signatrue
2.生成signature需要通過appid和secret獲取token
3.時間戳和調用接口URL必不可少
4.此操作需要服務端完成,不能使用客戶端實現
整個過程變成:
1.通過appid和secret獲取access_token,接著使用token獲取jsapi_ticket;
2.拿到jsapi_ticket之后,把jsapi_ticket、時間戳、隨機字符串、接口調用頁面URL 拼接成完整字符串,使用sha1算法加密得到signature。
3.最后返回至頁面,在wx.config里面填入appid,上一步的時間戳timestamp,上一部的隨機字符串、sha1拿到的signature,想要使用的JS接口。
廢話少說,直接上代碼吧。
代碼時間
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
|
public class WeiXinController : Controller { public static readonly string appid = System.Web.Configuration.WebConfigurationManager.AppSettings[ "wxappid" ]; public static readonly string secret = System.Web.Configuration.WebConfigurationManager.AppSettings[ "wxsecret" ]; public static readonly bool isDedug = System.Web.Configuration.WebConfigurationManager.AppSettings[ "IsDebug" ] == "true" ; public static string _ticket = "" ; public static DateTime _lastTimestamp; public ActionResult Info( string url, string noncestr) { if ( string .IsNullOrEmpty(_ticket) || _lastTimestamp == null || (_lastTimestamp - DateTime.Now).Milliseconds > 7200) { var resultString = HTTPHelper.GetHTMLByURL( "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=" + appid + "&secret=" + secret); dynamic resultValue = JsonConvert.DeserializeObject<dynamic>(resultString); if (resultValue == null || resultValue.access_token == null || resultValue.access_token.Value == null ) { return Json( new { issuccess = false , error = "獲取token失敗" }); } var token = resultValue.access_token.Value; resultString = HTTPHelper.GetHTMLByURL token + "&type=jsapi" ); dynamic ticketValue = JsonConvert.DeserializeObject<dynamic>(resultString); if (ticketValue == null || ticketValue.errcode == null || ticketValue.errcode.Value != 0 || ticketValue.ticket == null ) return Json( new { issuccess = false , error = "獲取ticketValue失敗" }); _ticket = ticketValue.ticket.Value; _lastTimestamp = DateTime.Now; var timestamp = GetTimeStamp(); var hexString = string .Format( "jsapi_ticket={0}&noncestr={3}×tamp={1}&url={2}" , _ticket, timestamp, url,noncestr); return Json( new { issuccess = true , sha1value = GetSHA1Value(hexString), timestamp = timestamp, url = url, appid = appid, debug=isDedug, tiket=_ticket }); } else { var timestamp = GetTimeStamp(); var hexString = string .Format( "jsapi_ticket={0}&noncestr=1234567890123456×tamp={1}&url={2}" , _ticket, timestamp, url); return Json( new { issuccess = true , sha1value = GetSHA1Value(hexString), timestamp = timestamp, url = url, appid = appid, debug = isDedug,tiket = _ticket }); } } private string GetSHA1Value( string sourceString) { var hash = SHA1.Create().ComputeHash(Encoding.UTF8.GetBytes(sourceString)); return string .Join( "" , hash.Select(b => b.ToString( "x2" )).ToArray()); } private static string GetTimeStamp() { TimeSpan ts = DateTime.Now - new DateTime(1970, 1, 1, 0, 0, 0, 0); return Convert.ToInt64(ts.TotalSeconds).ToString(); } } public class HTTPHelper { public static string GetHTMLByURL( string url) { string htmlCode = string .Empty; try { HttpWebRequest webRequest = (System.Net.HttpWebRequest)System.Net.WebRequest.Create(url); webRequest.Timeout = 30000; webRequest.Method = "GET" ; webRequest.UserAgent = "Mozilla/4.0" ; webRequest.Headers.Add( "Accept-Encoding" , "gzip, deflate" ); HttpWebResponse webResponse = (System.Net.HttpWebResponse)webRequest.GetResponse(); //獲取目標網站的編碼格式 string contentype = webResponse.Headers[ "Content-Type" ]; Regex regex = new Regex( "charset\\s*=\\s*[\\W]?\\s*([\\w-]+)" , RegexOptions.IgnoreCase); if (webResponse.ContentEncoding.ToLower() == "gzip" ) //如果使用了GZip則先解壓 { using (System.IO.Stream streamReceive = webResponse.GetResponseStream()) { using (var zipStream = new System.IO.Compression.GZipStream(streamReceive, System.IO.Compression.CompressionMode.Decompress)) { //匹配編碼格式 if (regex.IsMatch(contentype)) { Encoding ending = Encoding.GetEncoding (regex.Match(contentype).Groups[1].Value.Trim()); using (StreamReader sr = new System.IO.StreamReader(zipStream, ending)) { htmlCode = sr.ReadToEnd(); } } else { using (StreamReader sr = new System.IO.StreamReader(zipStream, Encoding.UTF8)) { htmlCode = sr.ReadToEnd(); } } } } } else { using (System.IO.Stream streamReceive = webResponse.GetResponseStream()) { var encoding = Encoding.Default; if (contentype.Contains( "utf" )) encoding = Encoding.UTF8; using (System.IO.StreamReader sr = new System.IO.StreamReader(streamReceive, encoding)) { htmlCode = sr.ReadToEnd(); } } } return htmlCode; } catch (Exception ex) { return "" ; } } } |
PS:這里要注意緩存一下_ticket(即access_token),照微信文檔說的,access_token兩個小時內有效,不需要頻繁調用。而且獲取access_token的接口有調用次數的限制,如果超過了次數,就不允許調用了。
PPS:建議noncestr和URL由前臺傳入比較適合,使用 var theWebUrl = window.location.href.split('#')[0] 獲取URL,noncestr就隨意了。
PPPS:遇到詭異的invalid signature的時候,首先檢查url參數,然后檢查noncestr,再不行重啟一下程序獲取一個新的token回來繼續玩。
以上就是本文的全部內容,希望對大家的學習有所幫助,也希望大家多多支持服務器之家。