摘要 近期在開發H5頁面相關需求,需求中有個微信靜默授權登錄的功能,之前沒有接觸過這個功能,經過調研官方文檔,開發出了初級方案;初級方案可以解決獲取code,但是頁面返回上一個頁面時,需要連續返回兩次才可以回到上一個頁面。經過獲取流程分析,解決了返回迴圈的bug。 初級方案原理 當時調研完官方文檔後 ...
摘要
近期在開發H5頁面相關需求,需求中有個微信靜默授權登錄的功能,之前沒有接觸過這個功能,經過調研官方文檔,開發出了初級方案;初級方案可以解決獲取code,但是頁面返回上一個頁面時,需要連續返回兩次才可以回到上一個頁面。經過獲取流程分析,解決了返回迴圈的bug。
初級方案原理
當時調研完官方文檔後,發現授權流程是重定向的方式,就傻白甜的直接在需要微信code的頁面直接獲取code並跳轉回當前頁,這樣就造成了頁面獲取死迴圈的bug。為瞭解決獲取code死迴圈的bug,在獲取code時,建立一個中間也獲取微信的code,code獲取後將code存儲到sessionStorage里,最後再重定向回頁面,具體流程如下圖所示:
·初級方案路由history
從路由history可以看出,初級方案建立一個微信獲取code的頁面,於是在路由的history多了一層授權的路由,所以返回作品列表需要連續返回兩次才會回到列表頁。路由history堆棧表如下圖所示:
終極方案原理
根據初級方案的授權模式進行改動,進入作品詳情頁判斷UrlCode和localCode是否都有值,值為空或者null,獲取微信code。當urlCode有值時,執行history.goback(),這樣既可以防止頁面迴圈獲取code刷新操作,又可以去除history中獲取微信code的歷史路由。具體流程示意圖如下所示:
·終極方案路由history
終極方案是直接在當前的作品頁獲取code並跳轉回作品頁,免去了一層調用獲取code頁組件的路由。這樣做會引起頁面迴圈獲取code,所以需要判斷urlcode和localcode來決定是否繼續迴圈獲取,還是做history.goback()。具體的路由history堆棧表如下圖所示:
React實現方案
理清了終極的微信靜默授權登錄實現方案,我們就可以根據思路來編寫我們需要的功能代碼了,個人在開發中是使用的React-Hook,所以就微信授權這個功能,自定義了一個useWxCode的可用hook。具體代碼如下:
import { useEffect } from 'react';
import { useHistory } from 'react-router-dom';
// 獲取用於微信授權的 code,卸載後會自動清除
export const useWxCode = () => {
const history = useHistory();
useEffect(()=>{const searchParams = new URLSearchParams(window.location.search);
const urlCode = searchParams.get('code');
const localCode = sessionStorage.getItem('code');
if (!urlCode && !localCode) {
const appid = 'xxxxxxxx'; // 微信授權的公眾號的appid
const redirectUrl = encodeURIComponent(window.location.href);
window.location.href = `https://open.weixin.qq.com/connect/oauth2/authorize?appid=${appid}&redirect_uri=${redirectUrl}&response_type=code&scope=snsapi_base&state=123#wechat_redirect`;
} else if (urlCode) {
sessionStorage.setItem('code', urlCode);
history.goBack();
}
return ()=>sessionStorage.removeItem('code');
},[]);
return sessionStorage.getItem('code');
}
組件中獲取授權的code:
import React from 'react';
// 引入useWxCode.js
import { useWxCode } from '@/utils/useWxCode';
const Test = () => {
const code = useWxCode();
return (
<div>
測試
</div>
)
}
export default Test;
參考: