什麼是無感刷新及其實現方式
- 1226字
- 6分鐘
- 2024-08-09
無感刷新是一種機制,允許前端應用在令牌快要過期時自動請求新的令牌,而不需要用戶的干預。這種方法可以提高用戶體驗,避免因令牌過期導致的登錄中斷。
實現無感刷新的常見方法
Token過期時間管理
- 當用戶登錄後,前端通常會存儲訪問令牌(如JWT)和刷新令牌。
- 訪問令牌通常有較短的有效期(如15分鐘),而刷新令牌有效期較長(如7天)。
- 前端在訪問令牌即將過期時(例如還剩2分鐘時),主動使用刷新令牌向後台請求新的訪問令牌。
攔截器(Interceptor)
- 前端應用可以使用攔截器(如在Axios或Fetch中)攔截所有請求。
- 如果檢測到當前訪問令牌已過期,攔截器會先使用刷新令牌獲取新的訪問令牌,再重新發送原始請求。
- 這樣,用戶感知不到任何中斷,應用也保持了連續的操作。
無感刷新邏輯
- 設置一個定時器,在令牌即將過期前自動觸發刷新操作。
- 定期檢查令牌的有效期,如果令牌快要過期則自動刷新,防止用戶操作被中斷。
- 如果刷新令牌也失效,則將用戶重定向到登錄頁面。
Silent Authentication(靜默認證)
- 對於部分前端應用,可以使用隱藏的iFrame來進行靜默認證,利用SSO機制在後台完成令牌的刷新,而不影響前台的用戶操作。
Axios 攔截器實現示例
以下是一個完整的Axios攔截器實現的代碼,用於處理JWT令牌的自動刷新和請求重試。在這個示例中,假設你已經有一個後端API可以提供刷新令牌的功能。
1. 創建Axios實例
首先,我們需要創建一個Axios實例,並配置請求攔截器和響應攔截器。
1import axios from "axios";2
3// 創建Axios實例4const apiClient = axios.create({5 baseURL: "https://api.example.com", // 替換為你的API基礎URL6 timeout: 10000,7});
2. 添加請求攔截器
在每個請求中添加Authorization頭部,以便將JWT訪問令牌包含在請求中。
1// 添加請求攔截器2apiClient.interceptors.request.use(3 (config) => {4 // 在每個請求中都帶上Authorization頭部5 const token = localStorage.getItem("token");6 if (token) {7 config.headers["Authorization"] = `Bearer ${token}`;8 }9 return config;10 },11 (error) => {12 // 處理請求錯誤13 return Promise.reject(error);14 },15);
3. 添加響應攔截器
處理401錯誤,並在令牌過期時使用刷新令牌獲取新的訪問令牌。
1// 添加響應攔截器2apiClient.interceptors.response.use(3 (response) => {4 // 直接返回響應數據5 return response;6 },7 async (error) => {8 const originalRequest = error.config;9
10 // 如果響應狀態碼是401且原始請求未被重試過11 if (12 error.response &&13 error.response.status === 401 &&14 !originalRequest._retry15 ) {16 originalRequest._retry = true;17 try {18 const refreshToken = localStorage.getItem("refreshToken");19 if (refreshToken) {20 // 發送刷新令牌請求21 const { data } = await axios.post(22 "https://api.example.com/auth/refresh",23 { token: refreshToken },24 );25
26 // 更新本地存儲的令牌27 localStorage.setItem("token", data.token);28
29 // 更新Authorization頭部30 axios.defaults.headers.common["Authorization"] =31 `Bearer ${data.token}`;32
33 // 重新發送原始請求34 originalRequest.headers["Authorization"] = `Bearer ${data.token}`;35 return apiClient(originalRequest);36 }37 } catch (refreshError) {38 // 如果刷新令牌也失效,重定向到登錄頁39 localStorage.removeItem("token");40 localStorage.removeItem("refreshToken");41 window.location.href = "/login";42 }43 }44
45 // 處理其他錯誤46 return Promise.reject(error);47 },48);49
50export default apiClient;
代碼解釋
-
Axios實例化:
使用axios.create()創建一個自定義的Axios實例apiClient,可以指定基礎URL和其他配置。
-
請求攔截器:
在每個請求發出之前,檢查是否存在JWT訪問令牌,如果存在,則將其添加到請求頭部Authorization中。
-
響應攔截器:
- 處理401錯誤:當伺服器返回401未授權錯誤時,意味著令牌可能已過期。
- 刷新令牌:如果刷新令牌存在,發送請求到刷新令牌的API端點以獲取新的訪問令牌。
- 更新令牌:將新的令牌存儲到本地,並更新Axios實例的默認請求頭,以便在後續請求中使用新的令牌。
- 重試原始請求:使用新的令牌重新發送原始請求。
-
刷新令牌失敗:
如果刷新令牌無效或已過期,清除本地存儲的令牌並將用戶重定向到登錄頁面。
如何使用
在應用中,可以使用apiClient
代替原始的Axios實例來發送HTTP請求:
1import apiClient from "./apiClient";2
3async function getUserData() {4 try {5 const response = await apiClient.get("/user/profile");6 console.log(response.data);7 } catch (error) {8 console.error("獲取用戶數據失敗:", error);9 }10}
這段代碼通過封裝的apiClient
發送請求,自動處理令牌的刷新和重試邏輯。
總結
通過以上方法,可以在前端應用中實現無感刷新,確保用戶在使用過程中不會因令牌過期而被打斷。這種機制提升了用戶體驗,使應用更加流暢。