業務場景描述
假設使用者正在填寫一個複雜的表單,由於表單內容繁多,使用者花費了很長時間才填完。這時,如果Token已經過期,系統會讓使用者重新登入,這種體驗顯然是非常糟糕的。為了避免這種情況,我們需要在Token即將過期或已經過期時,自動重新整理Token,而不影響使用者正在進行的操作。
技術實現思路
一、準備工作
- 前端框架選擇:本文以Vue.js為例,結合Vue Router和Axios來實現Token無感重新整理機制。
- 後端支援:後端需要提供重新整理Token的介面,當接收到舊的Token時返回一個新的Token。
二、關鍵技術點
- 攔截請求:使用Axios攔截器來檢測每一個請求的狀態,如果發現Token過期,則觸發重新整理Token的邏輯。
- 重新整理Token:實現一個專門用於重新整理Token的方法,該方法會在舊的Token過期時自動呼叫並更新Token。
- 請求佇列:在重新整理Token期間,暫停其他需要Token的請求,待Token重新整理成功後,重新傳送這些請求。
三、具體實現步驟
1. 配置Axios攔截器
首先,配置Axios攔截器來檢測請求和響應的狀態,並在Token過期時觸發重新整理Token的邏輯。
import axios from 'axios'; import store from './store'; // 假設使用Vuex來管理全域性狀態 import router from './router'; let isRefreshing = false; let requests = []; axios.interceptors.request.use( config => { const token = store.state.token; if (token) { config.headers['Authorization'] = 'Bearer ' + token; } return config; }, error => { return Promise.reject(error); } ); axios.interceptors.response.use( response => { return response; }, error => { const { config, response } = error; const originalRequest = config; if (response && response.status === 401) { if (!isRefreshing) { isRefreshing = true; return refreshToken().then(newToken => { store.commit('setToken', newToken); originalRequest.headers['Authorization'] = 'Bearer ' + newToken; processQueue(null, newToken); return axios(originalRequest); }).catch(err => { processQueue(err, null); store.commit('logout'); router.push('/login'); return Promise.reject(err); }).finally(() => { isRefreshing = false; }); } else { return new Promise((resolve, reject) => { requests.push((token) => { originalRequest.headers['Authorization'] = 'Bearer ' + token; resolve(axios(originalRequest)); }); }); } } return Promise.reject(error); } ); function processQueue(error, token = null) { requests.forEach(promise => { if (error) { promise.reject(error); } else { promise.resolve(token); } }); requests = []; }
2. 實現重新整理Token的方法
接下來,實現一個用於重新整理Token的方法refreshToken
。這個方法會呼叫後端介面來獲取新的Token。
function refreshToken() { return new Promise((resolve, reject) => { axios.post('/auth/refresh', { refreshToken: store.state.refreshToken }).then(response => { if (response.data.success) { resolve(response.data.token); } else { reject(response.data.message); } }).catch(error => { reject(error); }); }); }
3. 更新Vuex狀態管理
確保在Vuex中有相關的狀態和方法來管理Token和使用者登入狀態。
const store = new Vuex.Store({ state: { token: localStorage.getItem('token') || '', refreshToken: localStorage.getItem('refreshToken') || '', user: {} }, mutations: { setToken(state, token) { state.token = token; localStorage.setItem('token', token); }, setRefreshToken(state, refreshToken) { state.refreshToken = refreshToken; localStorage.setItem('refreshToken', refreshToken); }, logout(state) { state.token = ''; state.refreshToken = ''; state.user = {}; localStorage.removeItem('token'); localStorage.removeItem('refreshToken'); } } });
4. 處理登入邏輯
確保在使用者登入時,正確地儲存Token和重新整理Token。
function login(credentials) { return axios.post('/auth/login', credentials).then(response => { store.commit('setToken', response.data.token); store.commit('setRefreshToken', response.data.refreshToken); }); }
總結:當使用者在填寫複雜表單時,即使Token過期也不會中斷他們的操作,從而提供了更好的使用者體驗。這個機制不僅適用於表單填寫,還可以廣泛應用於任何需要長時間互動的Web應用場景中。