##引言javascript
最近作一個微信webapp單頁應用項目,項目只須要獲取用戶的openid
;爲了更好的用戶體驗,整個過程讓用戶無感知,咱們採用靜默受權的方式來獲取openid;具體能夠翻看微信開發者文檔--微信網頁受權部分。前端
按照微信開發文檔的步驟操做,很容易的就實現了獲取openid的功能。到此你可能心中竊喜,so easy!若是你認爲實現到此結束,那麼極可能qa就會找上來,而且還現場給你演示問題來源現場(以下圖):java
<img src="https://images2018.cnblogs.com/blog/408483/201805/408483-20180503110201951-1315768611.gif" width="250" height="400" />git
在受權後重定向的回調頁面(例如上面例子的下單頁面)點擊返回,怎麼點擊都不能返回到正確的頁面,一直在這裏跳轉死循環了,到底該如何解決呢?下面就給出一種實踐方案。github
跳轉死循環的緣由,稍加分析就能知道緣由。項目中須要openid的頁面會靜默獲取openid(通常建議在項目入口文件獲取,而後緩存起來供其餘頁面使用);web
比方說上面在下單頁須要openid,這個時候當進入該頁面時,就會重定向到微信獲取受權頁面:api
https://open.weixin.qq.com/connect/oauth2/authorizeappid=APPID&redirect_uri=REDIRECT_URI&response_type=code&scope=SCOPE&state=STATE#wechat_redirect
受權成功後會重定向到回調連接地址(上面例子中的下單頁),並會帶上code參數。咱們在實現時是使用location.replace
將下單頁歷史記錄替換爲微信受權頁面。瀏覽器
總的來講,一次受權瀏覽器歷史記錄增長了1條記錄。那麼受權成功後瀏覽器歷史記錄究竟是怎麼樣的呢?緩存
理論上,上述過程瀏覽器歷史記錄應該是下圖所示的結果:微信
<img src="https://images2018.cnblogs.com/blog/408483/201805/408483-20180503113418852-92384063.png" width="600" height="300" />
可是通過在微信裏面測試,發現並非這樣的,而是以下圖所示,懷疑是微信瀏覽器作了特殊處理。
<img src="https://images2018.cnblogs.com/blog/408483/201805/408483-20180504001400254-1155925143.png" width="600" height="300" />
這樣在受權成功後的重定向頁面點擊微信返回按鈕,即上例中從下單頁點擊返回,會返回到不帶code參數的下單頁也就是第一次進入時的下單頁;然而頁面不作特殊處理的話,它會跳轉到微信受權頁面再次進行受權後又會重定向到指定的回調頁面即下單頁,這樣就會形成跳轉死循環的問題,表象上一直停留在下單頁,沒法進入項目指定的其餘頁面。
<img src="https://images2018.cnblogs.com/blog/408483/201805/408483-20180504001837938-862241007.png" width="400" height="300" />
經過對整個過程的分析,咱們能夠知道若是不作任何處理,只是在下單頁獲取受權後url中攜帶的code
參數,就會出現這種死循環的問題,那麼可否在受權頁面指定的redirect_uri
頁面(本例的下單頁)作一下處理呢,知足某個條件就不在跳往到微信受權頁?
答案固然是能夠的,一種實現方案能夠是這樣的:
指定一個用於受權成功後的回調連接redirect url,域名得和前端業務域名一致,而且整個連接是須要在微信開發者後臺配置的。
在進入步驟1指定的頁面後,前端須要獲取url參數code和sessionStorage中的code值,根據兩者code是否均有值來判斷是否須要重定向的微信受權頁面
在步驟2中兩種狀況下的code值都爲空時,前端使用**location.replace(url)**方法來跳轉到微信受權頁面,受權成功後跳轉到步驟1指定的回調頁面。此時瀏覽器歷史記錄只增長了1條,即微信受權頁面歷史記錄
在步驟2設置的回調頁面中,若url的code參數有值且sessionStorage獲取的code值爲null時,將url的code參數值存到sessionStorage中,而後history.back()
在history.back()執行後,就又回到受權連接跳轉以前的那個頁面,即進入未跳轉前的下單頁。
再次點擊微信返回按鈕,就能夠正常返回了
具體的代碼實現部分以下:
const params = getQueryParams() const code = sessionStorage.getItem('code') if (!params.code && !code) { let url = `https://open.weixin.qq.com/connect/oauth2/authorize?appid=${yourAppId}&redirect_uri=${encodeURIComponent(location.href)}&response_type=code&scope=snsapi_base&state=1#wechat_redirect` window.location.replace(url) } else if(!code){ sessionStorage.setItem('code', params.code) history.back() }