最近遇到这个需求,前端登录后,后端返回 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)) }) }) } } }
第一次的请求没有放到那个队列中