业务场景:有几个外部系统的接口,需要先通过一个获取 token 的接口获取到 token 后续业务接口需要在请求头中的 Authorization 带上 token。刚开始我在登录后获取了一次 token 并存储在 store 中,业务接口使用过的时候直接获取就可以了。后来发现这个 token 经常莫名其妙的过期,刚开始想着通过同步获取 token 后再请求业务接口,但是这些业务接口分散在多个子页面中,就会造成多写很多业务代码。所决定在这些外部接口使用一个特定的 axios 实例并在 response 的拦截处统一处理 token 问题
axios 实例代码:
import axios from 'axios'
import store from '@/store'
import { getTokenInfo } from '@/api/prophetApiMarket'
import { Message } from 'element-ui'
import debounce from 'lodash/debounce'
// 多个错误信息合并
const showMessage = debounce(function (message) {
Message({
message: message,
type: 'error',
duration: 3 * 1000
})
}, 300)
// 最大重复次数
const MAXREPEAT = 3
// 记录当前接口重复请求次数,超过3次就不再请求了
let countState = {}
// 重新设置token
async function refreshToken(ajax, response) {
// 获取token,data就是token字符串
const { data } = await getTokenInfo()
store.commit("setProphetToken", data)
// 重新请求当前之前没有token 的接口
response.config.headers['Authorization'] = "Bearer " + data
ajax.defaults.headers.common['Authorization'] = "Bearer " + data
}
// 初始实例
const ajax = axios.create({
timeout: 10000,
baseURL: '/prop'
})
// 返回拦截
ajax.interceptors.response.use(async response => {
if (response.status === 200) {
const { data } = response
// token过期
if (data.code === 403 || (data.code === 406 && data.message === 'TOKEN已过期')) {
countState[response.config.url] = countState[response.config.url] ?? 0
// 最大重复次数
if (countState[response.config.url] < MAXREPEAT) {
// 计数
countState[response.config.url]++
// 获取token
await refreshToken(ajax, response)
// 重新请求
return ajax(response.config)
} else {
// 重置计数,并返回结果
countState[response.config.url] = 0
return data
}
}
return data
} else {
console.log('responseError: ' + response.data.message)
showMessage(response.data.message)
return Promise.resolve(response)
}
}, error => {
console.log('responseError: ' + error)
showMessage(error.message)
})
export default ajax
引入上面文件使用:
import ajax from './request.js'
import store from '@/store'
// getToken
export const getTokenInfo = () => {
return ajax.post('/aaaa', {
secretKey: store.state.envVar.key,
userId: store.state.envVar.id
})
}
// getDataA
export const getDataA= (params) => {
return ajax.post('/getDataA', params)
}
上面的 getDataA 是需要设置 Authorization 请求头的,当调用之后,response 拦截且匹配到 token 已过期就会先去获取 token 然后再重新请求
axios使用详见官网:axios中文文档|axios中文网