最近開發微信公衆號內嵌H5頁面,使用vue搭建的項目,因爲業務需求,須要實現微信自定義分享功能,因此項目中集成微信JS-SDK。微信JS-SDK是微信公衆平臺面向網頁開發者提供的基於微信內的網頁開發工具包。經過使用微信JS-SDK,網頁開發者可藉助微信高效地使用拍照、選圖、語音、位置等手機系統的能力,同時能夠直接使用微信分享、掃一掃、卡券、支付等微信特有的能力,爲微信用戶提供更優質的網頁體驗。html
微信公衆號開發測試賬號:http://mp.weixin.qq.com/debug...,須要填寫接口配置,一個公網能訪問的域名,推薦用natapp/路由俠。填寫JS接口安全域名 ,設置JS接口安全域後,經過關注該測試號,開發者便可在該域名下調用微信開放的JS接口,請閱讀微信JSSDK開發文檔
1)這裏使用路由俠,實現內網穿透http://www.luyouxia.com/,下載安裝後,配置相應的內網映射地址
前端
2)設置JS接口安全域
vue
經過npm安裝微信的js-sdk,或者在index.html頁面中直接加script標籤來引用,這裏採用npm安裝,npm install weixin-js-sdk
在須要分享的頁面中引入import wx from 'weixin-js-sdk'
java
1)jsapi_ticket
生成簽名以前必須先了解一下jsapi_ticket,jsapi_ticket是公衆號用於調用微信JS接口的臨時票據。正常狀況下,jsapi_ticket的有效期爲7200秒,經過access_token來獲取。因爲獲取jsapi_ticket的api調用次數很是有限,頻繁刷新jsapi_ticket會致使api調用受限,影響自身業務,開發者必須在本身的服務全局緩存jsapi_ticket。ios
2)獲取access_token(有效期7200秒,開發者必須在本身的服務全局緩存access_token)
access_token是公衆號的全局惟一接口調用憑據,公衆號調用各接口時都需使用access_token,官方文檔:https://mp.weixin.qq.com/wiki...web
@RequestMapping(value = "/get_access_token", method = RequestMethod.GET) public String getAssessToken() { String url = "https://api.weixin.qq.com/cgi-bin/token"; String str = HttpClientUtil.sendGet(url, "grant_type=" + Constants.GRANTTYPE + "&secret=" + Constants.APPSECRET + "&appid=" + Constants.APPID); JSONObject jsonObject = JSONObject.fromObject(str); return jsonObject.toString(); }
3)獲取access_token後,採用http GET方式請求得到jsapi_ticket算法
@RequestMapping(value = "/get_ticket", method = RequestMethod.GET) public String getTicket() { String urlToken = "https://api.weixin.qq.com/cgi-bin/token"; String tokenObj = HttpClientUtil.sendGet(urlToken, "grant_type=" + Constants.GRANTTYPE + "&secret=" + Constants.APPSECRET + "&appid=" + Constants.APPID); JSONObject jsonToken = JSONObject.fromObject(tokenObj); String access_token = jsonToken.getString("access_token"); String urlTicket = "https://api.weixin.qq.com/cgi-bin/ticket/getticket"; String strTicket = HttpClientUtil.sendGet(urlTicket, "type=jsapi" + "&access_token=" + access_token); JSONObject jsonTicket = JSONObject.fromObject(strTicket); return jsonTicket.toString(); }
4)簽名算法
簽名生成規則以下:參與簽名的字段包括noncestr(隨機字符串), 有效的jsapi_ticket, timestamp(時間戳), url(當前網頁的URL,不包含#及其後面部分) 。對全部待簽名參數按照字段名的ASCII 碼從小到大排序(字典序)後,使用URL鍵值對的格式(即key1=value1&key2=value2…)拼接成字符串string1。這裏須要注意的是全部參數名均爲小寫字符。對string1做sha1加密,字段名和字段值都採用原始值,不進行URL 轉義。數據庫
@RequestMapping(value = "/get_signature", method = RequestMethod.GET) public Map<String, String> getSignature(String url) { Map<String, String> ret = new HashMap<String, String>(); String wxTicket = getWxApiTicket(); String nonce_str = create_nonce_str(); String timestamp = create_timestamp(); String str; String signature = ""; //注意這裏參數名必須所有小寫,且必須有序 str = "jsapi_ticket=" + wxTicket + "&noncestr=" + nonce_str + "×tamp=" + timestamp + "&url=" + url; logger.info(str); try { MessageDigest crypt = MessageDigest.getInstance("SHA-1"); crypt.reset(); crypt.update(str.getBytes("UTF-8")); signature = byteToHex(crypt.digest()); } catch (NoSuchAlgorithmException e) { e.printStackTrace(); } catch (UnsupportedEncodingException e) { e.printStackTrace(); } ret.put("url", url); ret.put("jsapi_ticket", wxTicket); ret.put("nonceStr", nonce_str); ret.put("timestamp", timestamp); ret.put("signature", signature); ret.put("appId", Constants.APPID); return ret; } private static String byteToHex(final byte[] hash) { Formatter formatter = new Formatter(); for (byte b : hash) { formatter.format("%02x", b); } String result = formatter.toString(); formatter.close(); return result; } private static String create_nonce_str() { return UUID.randomUUID().toString(); } private static String create_timestamp() { return Long.toString(System.currentTimeMillis() / 1000); }
簽名接口返回信息
npm
{ "signature":"4021b3f502e6bd15798a0433af33c4ef1be4ff83", "appId":"wx618f45e4948c3889", "jsapi_ticket":"sM4AOVdWfPE4DxkXGEs8VOxnOWlkG3Q1qP1pwA8mBLNgkCewNOfFiU8EmlnAx8_Fe0Zh-rGS03Nu8BQZB0a4-g", "url":null, "nonceStr":"ab5d0e96-429b-4a86-bd88-dc1276dcf76f", "timestamp":"1566527616" }
注意事項
1.簽名用的noncestr和timestamp必須與wx.config中的nonceStr和timestamp相同。
2.簽名用的url必須是調用JS接口頁面的完整URL。
3.出於安全考慮,開發者必須在服務器端實現簽名的邏輯。json
全部須要使用JS-SDK的頁面必須先注入配置信息,不然將沒法調用(同一個url僅需調用一次,對於變化url的SPA的web app可在每次url變化時進行調用,目前Android微信客戶端不支持pushState的H5新特性,因此使用pushState來實現web app的頁面會致使簽名失敗,此問題會在Android6.2中修復)。
wx.config({ debug: true, // 開啓調試模式,調用的全部api的返回值會在客戶端alert出來,若要查看傳入的參數,能夠在pc端打開,參數信息會經過log打出,僅在pc端時纔會打印。 appId: '', // 必填,公衆號的惟一標識 timestamp: , // 必填,生成簽名的時間戳 nonceStr: '', // 必填,生成簽名的隨機串 signature: '',// 必填,簽名 jsApiList: [] // 必填,須要使用的JS接口列表 });
config配置裏面的參數appid, timestamp, nonceStr, signature都是要後臺接口返回的,前端能夠經過axios發送接口請求獲取
this.axios.get('/wx/get_signature?url=' + encodeURIComponent(location.href.split('#')[0])).then((res) => { wx.config({ debug: true, // 開啓調試模式 appId: res.data.appId, // 必填,公衆號的惟一標識 timestamp: res.data.timestamp, // 必填,生成簽名的時間戳 nonceStr: res.data.nonceStr, // 必填,生成簽名的隨機串 signature: res.data.signature,// 必填,簽名 jsApiList: [ "updateAppMessageShareData",//自定義「分享給朋友」及「分享到QQ」按鈕的分享內容 "updateTimelineShareData",//自定義「分享到朋友圈」及「分享到QQ空間」按鈕的分享內容 "onMenuShareWeibo",//獲取「分享到騰訊微博」按鈕點擊狀態及自定義分享內容接口 ] // 必填,須要使用的JS接口列表 }) }).catch((error) => { console.log(error) }); //經過ready接口處理成功驗證 wx.ready(function(){ this.wxShareTimeline(); this.wxShareAppMessage(); // config信息驗證後會執行ready方法,全部接口調用都必須在config接口得到結果以後,config是一個客戶端的異步操做,因此若是須要在頁面加載時就調用相關接口,則須把相關接口放在ready函數中調用來確保正確執行。對於用戶觸發時才調用的接口,則能夠直接調用,不須要放在ready函數中。 }); wx.error(function(res){ //config信息驗證失敗會執行error函數,如簽名過時致使驗證失敗,具體錯誤信息能夠打開config的debug模式查看,也能夠在返回的res參數中查看,對於SPA能夠在這裏更新簽名。 });
wxShareTimeline() {// 自定義「分享給朋友」及「分享到QQ」按鈕的分享內容 wx.updateAppMessageShareData({ title: '世界那麼大,我想去看看-微信test', // 分享標題 desc: '世界那麼大,我想去看看-微信test', // 分享描述 link: location.href.split('#')[0], // 分享連接,該連接域名或路徑必須與當前頁面對應的公衆號JS安全域名一致 imgUrl: 'http://www.baidu.com/FpEhdOqBzM8EzgFz3ULByxatSacH', // 分享圖標 success: () => { } }) }, wxShareAppMessage() {//自定義「分享到朋友圈」及「分享到QQ空間」按鈕的分享內容 wx.updateTimelineShareData({ title: '世界那麼大,我想去看看-微信test2', // 分享標題 desc: '世界那麼大,我想去看看-微信test2', // 分享描述 link: location.href.split('#')[0], // 分享連接,該連接域名或路徑必須與當前頁面對應的公衆號JS安全域名一致 imgUrl: require('./logo.jpg'), // 分享圖標(不能賦相對路徑,必定要是絕對路徑) success: () => { } }) }
1)invalid signature
獲取的簽名錯誤,緣由多是公衆號平臺配置有問題或者是後臺返回簽名接口的算法有問題
2)invalid url domain
當前頁面所在域名與使用的appid沒有綁定,請確認正確填寫綁定的域名,僅支持80(http)和443(https)兩個端口,所以不須要填寫端口號。
3)自定義的縮略圖不顯示
路徑錯誤致使的,不能使用相對路徑,必定要是絕對路徑,另一個緣由就是圖片尺寸和類型問題,推薦使用jpg格式
4)二次分享致使不能調用自定義的接口
url進行編碼以後傳給後臺獲取的簽名纔不會計算錯,由於微信會在分享後的連接後面加from=singlemessage&isappinstalled=0這串字符串。
1)經過數據庫保存
作法是獲取access_token的時候把當前系統時間和access_token保存到數據表中,當再次獲取時,查詢上次獲取的時間與當前系統時間比較,看看時間是否大於2個小時(7200s)。若是超過這個時間限制,再獲取一個access_token,而後更新數據表的accessToken和getTime。
2)經過物理磁盤建立txt文件保存
3)經過servlet啓動線程,讓線程定時執行獲取
能夠參考https://blog.csdn.net/guobinh...
以上即是此次調用微信js-sdk總結,想要了解更多能夠閱讀微信JS-SDK說明文檔https://mp.weixin.qq.com/wiki...