1. 程式人生 > 實用技巧 >解決vue單頁面應用做微信JSSDK注入許可權時出現“invalid signature”(ios端)

解決vue單頁面應用做微信JSSDK注入許可權時出現“invalid signature”(ios端)

——都說微信開發多坑,沒想到遇到一個天坑。

在做一個vue專案時,要用到微信JS-SDK,官方文件詳見:https://developers.weixin.qq.com/doc/offiaccount/OA_Web_Apps/JS-SDK.html

將當前頁面url傳給後端介面,再通過返回的配置資訊,用wx.config成功注入,一切看起來很順利,在安卓上執行沒問題,在iphone上測試,發現瀏覽器剛進入時(註冊頁做了注入)沒報錯,登入後也沒錯,一登入再退出就報“invalid signature”,再登入回首頁(首頁也做了注入),也報簽名錯誤,一重新整理又正常了。檢查傳的url也是當前頁面url,有點奇怪。以為這只是小小的bug,沒想到後來進入了一個“漫長艱辛”的探索之旅...

首先,官方文件有提到這個常見錯誤及解決方法,一一仔細檢視過,連報錯的簽名都用https://mp.weixin.qq.com/debug/cgi-bin/sandbox?t=jsapisign頁面工具校驗過,都沒問題。

然後,去網上一查ios注入許可權是否有不同,果然找到原來單頁面應用還真的不一樣!!!

在微信官方文件有這麼一句話:

所有需要使用JS-SDK的頁面必須先注入配置資訊,否則將無法呼叫(同一個url僅需呼叫一次,對於變化url的SPA的web app可在每次url變化時進行呼叫,目前Android微信客戶端不支援pushState的H5新特性,所以使用pushState來實現web app的頁面會導致簽名失敗,此問題會在Android6.2中修復)。

但在實際測試中,安卓並沒問題,反而是iphone有問題,應該是安卓版本做了修復。此為第一坑。

繼續查資料得知,在ios上,無論路由切換到哪個頁面,實際真正有效的的簽名url是【第一次進入應用時的URL】。

從A頁面跳轉到B頁面時,由於是使用vue-router切換,都是操作瀏覽器歷史記錄,所以ios端微信瀏覽器鎖定的url的還是A頁面的url。

比如進入應用首頁是: https://m.app.com,需要使用JSSDK的頁面A是:https://m.app.com/test/123,無論從首頁進入到A頁面之前,中間跳轉過多少次路由,最終簽名有效的url還是首頁url。

很多文件都是說history路由模式有問題,而hash模式沒問題,但我用的hash模式依舊簽名錯誤。此為第二坑。

再來,既然是第一次進入應用時的url,那我進入應用時就把當前url儲存到vuex裡面,永久儲存在localstorage,每次進入都是拿這個去注入許可權不就行了。

在main.js裡判斷是否是ios和vuex儲存的這個url是否為空,為空則存入當前url:

1 router.beforeEach((to, from, next) => {
2     if (isIOS() && store.state.user.wechatSignUrl === "") {
3         store.dispatch("user/setWechatSignUrl", location.href.split("#")[0]);
4     }
5 });

開啟後發現剛進入沒問題,註冊頁也ok,登入後沒錯,感覺到勝利在望時,一退出登入又報錯,關閉微信瀏覽器再進入,就一直報錯。。。

經過苦苦思索,突然靈光一現,想到這裡說的【第一次進入應用時的URL】,應該指的是頁面載入、過載或重新整理後第一次進入頁面時的url,之後無論路由怎麼切換url都不變,所以每次整個頁面載入或重新整理都要清空wechatSignUrl,在再次進入時就儲存當前url,這樣才能鎖定真正能用來簽名的url。此為第三坑。

那麼為什麼每次退出後的url就失效了呢?原來退出後用了頁面過載,還做了微信網頁授權,微信網頁授權要引導使用者開啟授權頁,使用者點選後再跳回來頁面算載入了一次,此時跳轉回來帶有code和state的這個url才是有效的簽名url!!!而不再是剛進入時的url。。(吐血ing)

所以退出後的頁面過載前要清空wechatSignUrl:

1   commit("SET_WECHAT_SIGN_URL", ""); //退出要過載 所以重置ios微信簽名地址
2   location.reload();

在跳轉到授權頁之前也清空wechatSignUrl:

1   store.dispatch("user/setWechatSignUrl", ""); //此處會跳到微信授權頁,頁面會重新整理,所以要重置簽名url
2   window.location.href = wechatAuth.authUrl;

我看了下,就這兩個地方需要頁面重新整理,其他都是路由切換,重新整理前清空,重新整理後再進入路由就會重新儲存當前的url,這個url就肯定是有效的了。

試了下,果然,開啟頁面後怎麼跳,怎麼退出再登入,不會再報“invalid signature”。

感覺已經可以收工了是不是?當我放心地關閉頁面再次點進去的時候,又報錯了!!!(心累)

只好繼續默默探索,關閉頁面再點進去也算載入,url也不能再用之前的了,所以關閉頁面前也要清空wechatSignUrl!還有微信瀏覽器還有個重新整理功能,重新整理頁面前也要清空,那麼怎麼監聽這個頁面關閉和重新整理功能呢?

網上說vue中監聽頁面重新整理和關閉可以用beforeunload,所以可以用:

1  // 當瀏覽器介面關閉或重新整理時觸發該事件 
2  window.addEventListener("beforeunload", () => {
3     this.$store.dispatch("user/setWechatSignUrl", "");
4  });

在pc端微信web開發者工具可以執行,但在手機上無論怎樣刷都保錯!!!

繼續深耕,原來用onbeforeunload來監聽使用者離開,瀏覽器可以,但是在微信中無效。微信瀏覽器不能用這個。此為第四坑。

經過查詢,微信瀏覽器監聽離開事件需要使用pagehide事件,關閉或重新整理可用。

所以在需要呼叫jssdk的頁面增加以下事件處理程式:

 1  mounted() {
 2     window.addEventListener("pagehide", this.pageHide);
 3  },
 4  destroyed() {
 5     //移除事件處理程式
 6     window.removeEventListener("pagehide", this.pageHide);
 7  },
 8  methods: {
 9    //頁面關閉或重新整理時觸發
10    pageHide() {
11      this.$store.dispatch("user/setWechatSignUrl", "");
12    },
13  }

此刻再測試,發現終於完美執行,無論怎麼關閉重新整理、跳轉過載都不再彈出“invalid signature”錯誤,天可憐見,看了多少文件,經過多少努力,才總算從這個天坑中爬出來了...^o^y...

ps:對於網上提到的第二種方法,是在進入呼叫jssdk的頁面之前,即beforeRouteEnter鉤子函式中用直接重新整理方式進入(location.href),此時頁面記錄的當前url就是有效的url,但實測並不成功,這樣頁面也會重新整理抖動太厲害不夠平滑過渡,不推薦使用。