微信內 H5 頁面自定義分享

JoeYoung發表於2021-06-08

起源:

最近公司在做一個活動的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。開發者需要進行妥善儲存。具體請參考以下官方文件:

https://link.zhihu.com/?target=https%3A//developers.weixin.qq.com/doc/offiaccount/Basic_Information/Get_access_token.html

公眾號和小程式均可以使用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&timestamp=1414587457&url=http://mp.weixin.qq.com?params=value

然後:對string1進行sha1簽名,得到signature。

signature=sha1(string1) // 0f9de62fce790f9a083d5c99e95740ceb90c27ed

注意事項

  1. 簽名用的noncestr和timestamp必須與wx.config中的nonceStr和timestamp相同。
  2. 簽名用的url必須是呼叫JS介面頁面的完整URL。
  3. 出於安全考慮,開發者必須在伺服器端實現簽名的邏輯。

 

前端需要做的:

參考官方文件: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物件)來呼叫,引數是一個物件,除了每個介面本身需要傳的引數之外,還有以下通用引數:

  1. success:介面呼叫成功時執行的回撥函式。
  2. fail:介面呼叫失敗時執行的回撥函式。
  3. complete:介面呼叫完成時執行的回撥函式,無論成功或失敗都會執行。
  4. cancel:使用者點選取消時的回撥函式,僅部分有使用者取消操作的api才會用到。
  5. 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.onMenuShareTimelinewx.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 不要帶有敏感詞彙。

 

相關文章