前端實(shí)現(xiàn)Token無感刷新的思路和具體實(shí)現(xiàn)方法
前言
在前端開發(fā)中,Token 無感刷新是一種常見的優(yōu)化技術(shù),用于在用戶無感知的情況下刷新過期的身份驗(yàn)證 Token,從而避免用戶因 Token 過期而需要重新登錄。以下是實(shí)現(xiàn) Token 無感刷新的思路和具體實(shí)現(xiàn)方法。
實(shí)現(xiàn)思路
Token 過期機(jī)制:
通常,身份驗(yàn)證 Token 有一個(gè)有效期(如 2 小時(shí))。
當(dāng) Token 過期后,用戶需要重新登錄或刷新 Token。
無感刷新的核心:
在 Token 過期前,通過刷新 Token 接口獲取新的 Token。
使用新的 Token 替換舊的 Token,并繼續(xù)用戶的請(qǐng)求。
實(shí)現(xiàn)步驟:
在請(qǐng)求攔截器中檢查 Token 是否即將過期。
如果 Token 即將過期,發(fā)起刷新 Token 的請(qǐng)求。
在響應(yīng)攔截器中處理 Token 過期的情況,重新發(fā)起失敗的請(qǐng)求。
具體實(shí)現(xiàn)
以下是一個(gè)基于 Axios 的 Token 無感刷新實(shí)現(xiàn)示例:
- 安裝 Axios
如果尚未安裝 Axios,可以通過以下命令安裝:
npm install axios
- 封裝 Axios 實(shí)例
創(chuàng)建一個(gè)封裝了 Token 無感刷新邏輯的 Axios 實(shí)例。
import axios from "axios"; // 創(chuàng)建 Axios 實(shí)例 const instance = axios.create({ baseURL: "https://api.example.com", timeout: 10000, }); // 存儲(chǔ) Token 和刷新 Token let token = localStorage.getItem("token") || ""; let refreshToken = localStorage.getItem("refreshToken") || ""; // 請(qǐng)求攔截器 instance.interceptors.request.use( (config) => { // 如果 Token 存在,添加到請(qǐng)求頭 if (token) { config.headers.Authorization = `Bearer ${token}`; } return config; }, (error) => { return Promise.reject(error); } ); // 響應(yīng)攔截器 instance.interceptors.response.use( (response) => { return response; }, async (error) => { const originalRequest = error.config; // 如果 Token 過期且未發(fā)起過刷新請(qǐng)求 if (error.response.status === 401 && !originalRequest._retry) { originalRequest._retry = true; // 標(biāo)記為已發(fā)起刷新請(qǐng)求 try { // 發(fā)起刷新 Token 的請(qǐng)求 const response = await axios.post("/refresh-token", { refreshToken, }); // 更新 Token 和刷新 Token const { token: newToken, refreshToken: newRefreshToken } = response.data; token = newToken; refreshToken = newRefreshToken; localStorage.setItem("token", newToken); localStorage.setItem("refreshToken", newRefreshToken); // 更新請(qǐng)求頭中的 Token originalRequest.headers.Authorization = `Bearer ${newToken}`; // 重新發(fā)起原始請(qǐng)求 return instance(originalRequest); } catch (refreshError) { // 刷新 Token 失敗,跳轉(zhuǎn)到登錄頁 localStorage.removeItem("token"); localStorage.removeItem("refreshToken"); window.location.href = "/login"; return Promise.reject(refreshError); } } return Promise.reject(error); } ); export default instance;
- 使用封裝的 Axios 實(shí)例
在項(xiàng)目中使用封裝好的 Axios 實(shí)例發(fā)起請(qǐng)求。
import axiosInstance from "./axiosInstance"; const fetchData = async () => { try { const response = await axiosInstance.get("/data"); console.log(response.data); } catch (error) { console.error("請(qǐng)求失敗", error); } }; fetchData();
關(guān)鍵點(diǎn)解析
Token 存儲(chǔ):
將 Token 和刷新 Token 存儲(chǔ)在 localStorage 或 sessionStorage 中。
每次請(qǐng)求時(shí)從存儲(chǔ)中讀取 Token。
請(qǐng)求攔截器:
在請(qǐng)求攔截器中,將 Token 添加到請(qǐng)求頭。
響應(yīng)攔截器:
在響應(yīng)攔截器中,檢查響應(yīng)狀態(tài)碼是否為 401(未授權(quán))。
如果 Token 過期,發(fā)起刷新 Token 的請(qǐng)求。
刷新成功后,更新 Token 并重新發(fā)起原始請(qǐng)求。
刷新 Token 接口:
后端需要提供一個(gè)刷新 Token 的接口(如 /refresh-token),接收 refreshToken 并返回新的 token 和 refreshToken。
錯(cuò)誤處理:
如果刷新 Token 失敗,清除本地存儲(chǔ)的 Token 并跳轉(zhuǎn)到登錄頁。
進(jìn)一步優(yōu)化
Token 過期時(shí)間檢查:
在請(qǐng)求攔截器中檢查 Token 的剩余有效期。
如果 Token 即將過期(如剩余 5 分鐘),提前刷新 Token。
const isTokenExpired = (token) => { const payload = JSON.parse(atob(token.split(".")[1])); const exp = payload.exp * 1000; // 轉(zhuǎn)換為毫秒 return Date.now() >= exp - 5 * 60 * 1000; // 提前 5 分鐘刷新 }; instance.interceptors.request.use( (config) => { if (token && isTokenExpired(token)) { // 發(fā)起刷新 Token 的請(qǐng)求 refreshToken() .then((newToken) => { token = newToken; localStorage.setItem("token", newToken); config.headers.Authorization = `Bearer ${newToken}`; }) .catch(() => { localStorage.removeItem("token"); window.location.href = "/login"; }); } return config; }, (error) => { return Promise.reject(error); } );
并發(fā)請(qǐng)求處理:
如果多個(gè)請(qǐng)求同時(shí)發(fā)現(xiàn) Token 過期,確保只發(fā)起一次刷新 Token 的請(qǐng)求。
使用一個(gè)標(biāo)志變量(如 isRefreshing)來控制刷新請(qǐng)求的并發(fā)。
安全性:
使用 HTTPS 加密傳輸 Token。
設(shè)置合理的 Token 有效期和刷新 Token 的有效期。
總結(jié)
通過 Axios 的請(qǐng)求攔截器和響應(yīng)攔截器,可以實(shí)現(xiàn) Token 的無感刷新,從而提升用戶體驗(yàn)。關(guān)鍵在于:
在 Token 過期前主動(dòng)刷新。
處理并發(fā)請(qǐng)求和錯(cuò)誤情況。
確保 Token 存儲(chǔ)和傳輸?shù)陌踩浴?/p>
這種方法適用于大多數(shù)前后端分離的項(xiàng)目,能夠有效減少用戶因 Token 過期而需要重新登錄的情況。
到此這篇關(guān)于前端實(shí)現(xiàn)Token無感刷新的思路和具體實(shí)現(xiàn)方法的文章就介紹到這了,更多相關(guān)前端Token無感刷新內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
js自動(dòng)閉合html標(biāo)簽(自動(dòng)補(bǔ)全html標(biāo)記)
假如我有一個(gè)DIV,如果沒有閉合后面的樣式都會(huì)亂了,這樣的代碼可能會(huì)影響后面的樣式,我希望用JS去自動(dòng)閉合這種沒有閉合的標(biāo)簽2012-10-10微信小程序使用checkbox顯示多項(xiàng)選擇框功能【附源碼下載】
這篇文章主要介紹了微信小程序使用checkbox顯示多項(xiàng)選擇框功能,涉及相關(guān)事件綁定與元素遍歷操作技巧,并附帶源碼供讀者下載參考,需要的朋友可以參考下2017-12-12webpack file-loader和url-loader的區(qū)別
這篇文章主要介紹了webpack file-loader和url-loader的區(qū)別,小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧2019-01-01js實(shí)現(xiàn)簡(jiǎn)單選項(xiàng)卡功能
這篇文章主要為大家詳細(xì)介紹了使用JS實(shí)現(xiàn)簡(jiǎn)單的選項(xiàng)卡功能,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2018-08-08詳解JavaScript如何實(shí)現(xiàn)四種常用排序
這篇文章主要為大家介紹了如何利用JavaScript實(shí)現(xiàn)四個(gè)常用的排序:插入排序、交換排序、選擇排序和歸并排序,文中利用動(dòng)圖詳細(xì)介紹了實(shí)現(xiàn)過程,需要的可以參考一下2022-02-02詳解JS轉(zhuǎn)換數(shù)值函數(shù)Number()、parseInt()、parseFloat()
JS中有三種函數(shù)可以將非數(shù)值轉(zhuǎn)換成數(shù)值:Number()、parseInt()和parseFloat()。接下來通過本文詳細(xì)的給大家介紹JS轉(zhuǎn)換數(shù)值函數(shù)Number()、parseInt()、parseFloat()的實(shí)例代碼,感興趣的朋友一起看看吧2018-08-08