起源:
最近公司在做一個活動的h5頁面,在微信內打開時需要進行微信授權,然后后端會重定向到這個頁面並且攜帶了一些參數(openid等)。問題是點擊微信的原生分享時,會把攜帶的這些參數一起分享出去,等於把用戶信息泄露了。所以為了解決這個問題,只能實現自定義微信分享的功能,可以自定義分享的地址、標題、圖標還有簡介。
事先需要做的:
1.微信公眾號:必須是經過微信認證的,沒有認證的或者認證過期的都不可以;
2.經過備案的域名:必須是備案過的,不然是無法使用的;
3.綁定域名:首先你需要將需要分享的網址的域名綁定到微信公眾平台上面,
具體操作:先登錄微信公眾平台進入“公眾號設置”的“功能設置”里填寫:JS接口安全域名;還要在"安全中心"中設置:IP白名單

后台需要做的:
1.后台服務器:前台頁面需要后台服務器傳過來一些配置參數,比如appId、timestamp、nonceStr、signature這幾個參數都是后台從微信公眾平台獲取到的, 需要后台進行配合;
2.獲取access_token:利用公共號APPID、APPSECRET從微信服務器獲取對應的access_token,這里是后台開發小伙伴的范圍不多做解釋;
后台需要傳的參數格式:

簽名的生成步驟:
生成簽名之前必須先了解一下jsapi_ticket,jsapi_ticket是公眾號用於調用微信JS接口的臨時票據。正常情況下,jsapi_ticket的有效期為7200秒,通過access_token來獲取。由於獲取jsapi_ticket的api調用次數非常有限,頻繁刷新jsapi_ticket會導致api調用受限,影響自身業務,開發者必須在自己的服務全局緩存jsapi_ticket 。
1. 獲取access_token(有效期7200秒,2個小時開發者必須在自己的服務全局緩存access_token):access_token是公眾號的全局唯一接口調用憑據,公眾號調用各接口時都需使用access_token。開發者需要進行妥善保存。具體請參考以下官方文檔:
公眾號和小程序均可以使用AppID和AppSecret調用本接口來獲取access_token。AppID和AppSecret可在“微信公眾平台-開發-基本配置”頁中獲得(需要已經成為開發者,且帳號沒有異常狀態)。調用接口時,請登錄“微信公眾平台-開發-基本配置”提前將服務器IP地址添加到IP白名單中,點擊查看設置方法,否則將無法調用成功。小程序無需配置IP白名單。示例代碼如下所示:
https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=APPID&secret=APPSECRET
返回的JSON如下:
{"access_token":"ACCESS_TOKEN","expires_in":7200}
2. 用第一步拿到的access_token 采用http GET方式請求獲得jsapi_ticket(有效期7200秒,2個小時,開發者必須在自己的服務全局緩存jsapi_ticket)
https://api.weixin.qq.com/cgi-bin/ticket/getticket?access_token=ACCESS_TOKEN&type=jsapi
成功返回JSON如下:
{ "errcode":0, "errmsg":"ok", "ticket":"bxLdikRXVbTPdHSM05e5u5sUoXNKd8-41ZO3MhKoyN5OfkWITDGgnr2fwJ0m9E8NYzWKVZvdVtaUgWvsdshFKA", "expires_in":7200 }
3. 生成JS-SDK權限驗證的簽名
參與簽名的字段包括noncestr(隨機字符串), 有效的jsapi_ticket, timestamp(時間戳), url(當前網頁的URL,不包含#及其后面部分) 。
首先:對所有待簽名參數按照字段名的ASCII 碼從小到大排序(字典序)后,使用URL鍵值對的格式(即key1=value1&key2=value2…)拼接成字符串string1:
順序依次為:jsapi_ticket,noncestr,timestamp,url。
jsapi_ticket=sM4AOVdWfPE4DxkXGEs8VMCPGGVi4C3VM0P37wVUCFvkVAy_90u5h9nbSlYy3-Sl-HhTdfl2fzFy1AOcHKP7qg&noncestr=Wm3WZYTPz0wzccnW×tamp=1414587457&url=http://mp.weixin.qq.com?params=value
然后:對string1進行sha1簽名,得到signature。
signature=sha1(string1) // 0f9de62fce790f9a083d5c99e95740ceb90c27ed
注意事項
- 簽名用的noncestr和timestamp必須與wx.config中的nonceStr和timestamp相同。
- 簽名用的url必須是調用JS接口頁面的完整URL。
- 出於安全考慮,開發者必須在服務器端實現簽名的邏輯。
前端需要做的:
參考官方文檔:https://developers.weixin.qq.com/doc/offiaccount/OA_Web_Apps/JS-SDK.html#3
1、在項目中引用微信的js-sdk
官方文檔上寫的是1.6.0
在需要調用JS接口的頁面引入如下JS文件,(支持https):http://res.wx.qq.com/open/js/jweixin-1.6.0.js
如需進一步提升服務穩定性,當上述資源不可訪問時,可改訪問:http://res2.wx.qq.com/open/js/jweixin-1.6.0.js (支持https)。
2、配置config
所有需要使用JS-SDK的頁面必須先注入配置信息,否則將無法調用。同一個url僅需調用一次,對於變化url的SPA的web app可在每次url變化時進行調用。其中的簽名信息signature需要服務器端提供。timestamp和nonceStr是參與簽名生成的字段,因此也可以由服務端一並提供,代碼如下所示:
wx.config({ debug: true, // 開啟調試模式,調用的所有api的返回值會在客戶端alert出來,若要查看傳入的參數,可以在pc端打開,參數信息會通過log打出,僅在pc端時才會打印。 appId: '', timestamp: , nonceStr: '', signature: '', jsApiList: [] });
參數說明:
- appId:公眾號的唯一標識,在公眾號中可以取到;
- timestamp:生成簽名的時間戳
- nonceStr: 生成簽名的隨機串
- signature: 最后生成的簽名
- jsApiList: 需要使用的JS接口列表,我們這里是用分享接口,將分享幾個api接口填進去,例如:['updateAppMessageShareData', 'updateTimelineShareData', 'onMenuShareQQ']
3、通過ready接口處理成功驗證
wx.ready(function(){ // config信息驗證通過后會執行ready方法, // 所有接口調用都必須在config接口獲得結果之后, // config是一個客戶端的異步操作,所以如果需要在頁面加載時就調用相關接口, // 則須把相關接口放在ready函數中調用來確保正確執行。 // 對於用戶觸發時才調用的接口,則可以直接調用,不需要放在ready函數中。 });
4、通過error接口處理失敗驗證
wx.error(function(res){ // config信息驗證失敗會執行error函數, // 如簽名過期導致驗證失敗,具體錯誤信息可以打開config的debug模式查看, // 也可以在返回的res參數中查看,對於SPA可以在這里更新簽名。 });
所有接口通過wx對象(也可使用jWeixin對象)來調用,參數是一個對象,除了每個接口本身需要傳的參數之外,還有以下通用參數:
- success:接口調用成功時執行的回調函數。
- fail:接口調用失敗時執行的回調函數。
- complete:接口調用完成時執行的回調函數,無論成功或失敗都會執行。
- cancel:用戶點擊取消時的回調函數,僅部分有用戶取消操作的api才會用到。
- trigger: 監聽Menu中的按鈕點擊時觸發的方法,該方法僅支持Menu中的相關接口。
備注:不要嘗試在trigger中使用ajax異步請求修改本次分享的內容,因為客戶端分享操作是一個同步操作,這時候使用ajax的回包會還沒有返回。
以上幾個函數都帶有一個參數,類型為對象,其中除了每個接口本身返回的數據之外,還有一個通用屬性errMsg,其值格式如下:
調用成功時:"xxx:ok" ,其中xxx為調用的接口名
用戶取消時:"xxx:cancel",其中xxx為調用的接口名
調用失敗時:其值為具體錯誤信息
官方示例代碼:
自定義“分享給微信朋友”及“分享到QQ好友”按鈕的分享內容(JSSDK 1.4.0以上版本支持):
wx.ready(function () { //需在用戶可能點擊分享按鈕前就先調用 wx.updateAppMessageShareData({ title: '', // 分享標題 desc: '', // 分享描述 link: '', // 分享鏈接,該鏈接域名或路徑必須與當前頁面對應的公眾號JS安全域名一致 imgUrl: '', // 分享圖標 success: function () { // 設置成功 } }) });
自定義“分享到朋友圈”及“分享到QQ空間”按鈕的分享內容(JSSDK 1.4.0以上版本支持):
wx.ready(function () { //需在用戶可能點擊分享按鈕前就先調用 wx.updateTimelineShareData({ title: '', // 分享標題 link: '', // 分享鏈接,該鏈接域名或路徑必須與當前頁面對應的公眾號JS安全域名一致 imgUrl: '', // 分享圖標 success: function () { // 設置成功 } }) });
獲取“分享給朋友”按鈕點擊狀態及自定義分享內容接口(即將廢棄):
wx.onMenuShareAppMessage({ title: '', // 分享標題 desc: '', // 分享描述 link: '', // 分享鏈接,該鏈接域名或路徑必須與當前頁面對應的公眾號JS安全域名一致 imgUrl: '', // 分享圖標 type: '', // 分享類型,music、video或link,不填默認為link dataUrl: '', // 如果type是music或video,則要提供數據鏈接,默認為空 success: function () { // 用戶點擊了分享后執行的回調函數 } });
獲取“分享到朋友圈”按鈕點擊狀態及自定義分享內容接口(即將廢棄):
wx.onMenuShareTimeline({ title: '', // 分享標題 link: '', // 分享鏈接,該鏈接域名或路徑必須與當前頁面對應的公眾號JS安全域名一致 imgUrl: '', // 分享圖標 success: function () { // 用戶點擊了分享后執行的回調函數 } },
獲取“分享到QQ”按鈕點擊狀態及自定義分享內容接口(即將廢棄):
wx.onMenuShareQQ({ title: '', // 分享標題 desc: '', // 分享描述 link: '', // 分享鏈接 imgUrl: '', // 分享圖標 success: function () { // 用戶確認分享后執行的回調函數 }, cancel: function () { // 用戶取消分享后執行的回調函數 } });
注意:
如果用舊版的 wx.onMenuShareTimeline、wx.onMenuShareAppMessage、wx.onMenuShareQQ 接口,請用1.4.0或者1.0.0的SDK。
我們用新接口的時候一直提示沒有權限,用原接口的時候提示簽名錯誤,后來換了1.0.0的SDK,后台又重新檢查了下簽名,並把 jsapi_ticket 緩存去掉。主要就是要一步步去測試,然后就神奇的好了。
完整的自定義分享代碼:
getWXShare() { axios.get('***/***/getShareTicket', MD5({ url: location.href }), function (data) { if (data.code === 200) { wx.config({ // debug: true, // 開啟調試模式,調用的所有api的返回值會在客戶端alert出來,若要查看傳入的參數,可以在pc端打開,參數信息會通過log打出,僅在pc端時才會打印。 appId: data.data.appId, //后台 必填,公眾號的唯一標識 timestamp: data.data.timestamp, // 必填,后台生成簽名的時間戳 nonceStr: data.data.nonceStr, // 必填,后台生成簽名的隨機串 signature: data.data.signature,// 必填,后台簽名 jsApiList: ['updateAppMessageShareData', 'updateTimelineShareData', 'onMenuShareAppMessage','onMenuShareTimeline', 'onMenuShareQQ', 'onMenuShareQZone'] }); wx.ready(function () { //分享到朋友圈(舊) wx.onMenuShareTimeline({ title: '要分享的標題', // 分享標題 desc: '要分享的簡介', link: "要分享的地址", // 分享鏈接, imgUrl: '要分享圖標', // 分享圖標 success: function () { // 用戶點擊了分享后執行的回調函數 // console.log("分享成功"); }, cancel: function () { // 用戶取消分享后執行的回調函數 // console.log("分享取消"); } }); // 朋友(舊) wx.onMenuShareAppMessage({ title: '要分享的標題', // 分享標題 desc: '要分享的簡介', link: "要分享的地址", // 分享鏈接, imgUrl: '要分享圖標', // 分享圖標 success: function () { // 用戶點擊了分享后執行的回調函數 // console.log("分享成功2"); }, cancel: function () { // 用戶取消分享后執行的回調函數 // console.log("分享取消2"); } }); }); //必須放wx.ready后面 否則無法執行 wx.error(function(res){ //config信息驗證失敗會執行error函數,如簽名過期導致驗證失敗,具體錯誤信息可以打開config的debug模式查看,也可以在返回的res參數中查看,對於SPA可以在這里更新簽名。 }); } else { alert('請稍后后再試') } }) },
總結
到這一步分享的操作基本就完成了,建議在測試時將debug打開,看看分享提示,從而判定是否分享成功。如果不成功,可以參考一下在開發時候遇到的坑。
- 出現nvalid url domain提示
1)檢查當前頁面所在域名與使用的appid沒有綁定,請確認正確填寫綁定的域名,僅支持80(http)和443(https)兩個端口,因此不需要填寫端口號。 - 出現invalid signature簽名錯誤提示
1)檢查生成signature是否正確,可以通過簽名校驗工具來判定后端傳過來的nonceStr、timestamp與請求后端接口傳的地址,與最后簽名是否一致。
2) config時,nonceStr 記得駝峰寫法。
3) 簽名用的url必須是調用JS接口頁面的完整URL,即當前頁面的完整URL。 - 提示是成功的,但是分享出來圖標不見或者desc不顯示的情況
1) 分享的地址不要帶端口號。
2)分享desc 不要帶有敏感詞匯。
新更新:(2021.12.20)
最近微信新修改了自定義分享規則,通過鏈接點進來的分享只能分享鏈接;通過分享和掃碼進來的可以分享鏈接+標題+縮略圖。(實測)
