在Vue应用中,我有一个响应拦截器:
axios.interceptors.response.use(function (config) {
return config;
}, error => {
if (error.response.status !== 401) {
return new Promise((resolve, reject) => {
reject(error);
});
}
if (error.response.status === 401 && error.response.data.message === 'Token Expired') {
this.store.dispatch('auth/refreshToken').then(aToken => {
var config = error.config;
axios.defaults.headers.common['Authorization'] = 'Bearer ' + aToken;
return new Promise((resolve, reject) => {
axios.request(config).then(response => {
console.log(response);
resolve(response);
}).catch((error) => {
reject(error);
});
});
});
}
});
...我正在刷新令牌,并使用新令牌再次发出最后一个(被拦截的)请求。
但是问题是,说我有一个组件Product.vue
,在安装组件时我正在向/products
端点发出请求。我将所有产品存储在该组件的products
数据变量中。假设用户现在处于/dashboard
路线中。他喝了一口咖啡,等他回来时,令牌已经过期了。他访问了/products
路由,响应为401,因此拦截器拦截了该响应,更新了令牌,然后尝试使用新令牌发出最后一个失败的请求。
但是没有从Product
组件执行此新请求。它是从拦截器执行的,在该拦截器中我无法访问Product
组件。因此,尽管请求成功,但是我的响应数据丢失了,并且由于products
变量为空,最终用户在视图中看不到任何内容。
是否可以跟踪哪个组件执行了请求并将其重新安装在拦截器中?我尝试了$router.push('/products')
,但是vue抛出异常,指出不允许导航到当前路线。
或者,有什么方法可以处理从Product组件中的拦截器返回的promise?
答案 0 :(得分:2)
您需要做的就是保持承诺链运行。目前,您由于不返回 dispatch 承诺而失去了它。
axios.interceptors.response.use(success => success, error => {
if (error.response.status === 401 && error.response.data.message === 'Token Expired') {
// return the new promise
// not sure what "this" is or why "store" is in it but hey, it's your code
return this.store.dispatch('auth/refreshToken').then(token => {
axios.defaults.headers.common.Authorization = `Bearer ${token}`
return axios.request(error.config)
})
}
return Promise.reject(error)
})
为说明起见,Axios的响应拦截器将自己插入到由请求创建的承诺链中。可以将它们想象为在您的调用代码接收到数据之前在请求的末尾添加额外的.then()
...
return axios.request({ ... })
.then(successInterceptor)
.catch(errorInterceptor)
在您的代码中,您不关心成功的响应,因此只返回原始响应
success => success
您的错误拦截器然后检查过期的令牌响应,并返回新的承诺,该承诺首先是更新令牌,然后重复原始请求(请参见Promise chaining)。
如果响应错误不是针对过期的令牌,则只需返回rejected promise来维护错误状态。如果您不这样做,那么被拒绝的承诺将成为成功的承诺,这将使您的调用代码very非常困惑。