需求
最近遇到個需求:前端登錄后,后端返回token和token有效時間,當token過期時要求用舊token去獲取新的token,前端需要做到無痛刷新token,即請求刷新token時要做到用戶無感知。
需求解析
當用戶發起一個請求時,判斷token是否已過期,若已過期則先調refreshToken接口,拿到新的token后再繼續執行之前的請求。
這個問題的難點在于:當同時發起多個請求,而刷新token的接口還沒返回,此時其他請求該如何處理?接下來會循序漸進地分享一下整個過程。
實現思路
由于后端返回了token的有效時間,可以有兩種方法:
方法一:
在請求發起前攔截每個請求,判斷token的有效時間是否已經過期,若已過期,則將請求掛起,先刷新token后再繼續請求。
方法二:
不在請求前攔截,而是攔截返回后的數據。先發起請求,接口返回過期后,先刷新token,再進行一次重試。
兩種方法對比
方法一
優點: 在請求前攔截,能節省請求,省流量。 缺點: 需要后端額外提供一個token過期時間的字段;使用了本地時間判斷,若本地時間被篡改,特別是本地時間比服務器時間慢時,攔截會失敗。PS:token有效時間建議是時間段,類似緩存的MaxAge,而不要是絕對時間。當服務器和本地時間不一致時,絕對時間會有問題。
方法二
優點:不需額外的token過期字段,不需判斷時間。
缺點: 會消耗多一次請求,耗流量。
綜上,方法一和二優缺點是互補的,方法一有校驗失敗的風險(本地時間被篡改時,當然一般沒有用戶閑的蛋疼去改本地時間的啦),方法二更簡單粗暴,等知道服務器已經過期了再重試一次,只是會耗多一個請求。
在這里博主選擇了 方法二。
實現
這里會使用axios來實現,方法一是請求前攔截,所以會使用axios.interceptors.request.use()這個方法;
而方法二是請求后攔截,所以會使用axios.interceptors.response.use()方法。
封裝axios基本骨架
首先說明一下,項目中的token是存在localStorage中的。request.js基本骨架:
import axios from 'axios'// 從localStorage中獲取tokenfunction getLocalToken () { const token = window.localStorage.getItem('token') return token}// 給實例添加一個setToken方法,用于登錄后將最新token動態添加到header,同時將token保存在localStorage中instance.setToken = (token) => { instance.defaults.headers['X-Token'] = token window.localStorage.setItem('token', token)}// 創建一個axios實例const instance = axios.create({ baseURL: '/api', timeout: 300000, headers: { 'Content-Type': 'application/json', 'X-Token': getLocalToken() // headers塞token }})// 攔截返回的數據instance.interceptors.response.use(response => { // 接下來會在這里進行token過期的邏輯處理 return response}, error => { return Promise.reject(error)})export default instance
新聞熱點
疑難解答
圖片精選