最近遇到這個需求,前端登錄后,后端返回 access_token 和 refresh_token ,當token 過期時用舊的 refresh_token 去獲取新的token,前端要不痛去刷新token 並用新請求的token 去將用戶發送的請求執行完 並返回希望的數據。
我這里用的時axios 來實現,在攔截器中去做相應的處理axios.interceptors.response.use()方法。
首先說明一下,項目中的token是存在localStorage中的。
比如返回的一個狀態值時token過期的狀態 那我們將在這個狀態下去處理,如果時同時又多個請求發送過來的話 需要將請求存起來
當第二個過期的請求進來,token正在刷新,我們先將這個請求存到一個數組隊列中,想辦法讓這個請求處於等待中,一直等到刷新token后再逐個重試清空請求隊列。 那么如何做到讓這個請求處於等待中呢?為了解決這個問題,我們得借助Promise。將請求存進隊列中后,同時返回一個Promise,讓這個Promise一直處於Pending狀態(即不調用resolve),此時這個請求就會一直等啊等,只要我們不執行resolve,這個請求就會一直在等待。當刷新請求的接口返回來后,我們再調用resolve,逐個重試。
下面時我實現的代碼
let retryRequest = [] //存放token 過期的請求
let isRefresh = false // 是否在請求新的token
// HTTPresponse攔截
axios.interceptors.response.use(res => {
const status = Number(res.status) || 200
if (status === 401) {
if (!isRefresh) {
isRefresh = true
return store.dispatch('RefreshToken',store.getters.refresh_token).then(data => {
// 這里是去請求新的token 並返回promise 然后保存新的token
store.commit('SET_ACCESS_TOKEN', data.data.access_token)
store.commit('SET_REFRESH_TOKEN', data.data.refresh_token)
res.config.headers['Authorization'] = data.data.access_token
retryRequest.forEach(cb => {
cb(data.data.access_token)
})
isRefresh = false
retryRequest = []
return axios(res.config)
})
}else {
return new Promise((resolve) => {
// 將resolve放進隊列,用一個函數形式來保存,等token刷新后直接執行
retryRequest.push((token) => {
res.config.headers['Authorization'] = token
resolve(axios(res.config))
})
})
}
}
}
第一次的請求沒有放到那個隊列中
