问题描述
我们最近在 这个问题.
拦截器应该做的是拦截任何带有 401
状态码的响应并尝试刷新令牌.考虑到这一点,接下来要做的是从拦截器返回一个 Promise,这样任何通常会失败的请求都会在令牌刷新后运行,而不会发生任何事情.
What the interceptor should do is intercept any response with the 401
status code and try to refresh the token.With that in mind, the next thing to do is to return a Promise from the interceptor, so that any request which would have normally fail, would run as nothing happens after a token refresh.
主要问题是,拦截器只检查401
状态码,这是不够的,因为refreshToken
也会返回401
代码>失败时的状态代码 - 我们有一个循环.
The main problem is, that an interceptor checks only the 401
status code, which is not enough, as the refreshToken
will also return the 401
status code when it fails - and we have a loop.
我想到了两种可能的情况:
There are two possible scenarios I have in mind:
- 检查被调用的 URL,所以如果它是
/auth/refresh
它不应该尝试刷新令牌; - 在调用
refreshToken
逻辑时省略拦截器
- check the called URL, so if that's
/auth/refresh
it shouldn't try to refresh the token; - omit an interceptor when the
refreshToken
logic is called
第一个选项看起来有点不动态";对我来说.第二种选择看起来很有希望,但我不确定它是否可能.
The first option looks a bit "not dynamic" to me. The second option looks promising, but I'm not sure if it's even possible.
然后,主要问题是,我们如何在没有硬编码"的情况下区分/识别拦截器中的调用并为它们运行不同的逻辑?具体来说,或者有什么方法可以省略指定调用的拦截器?提前致谢.
The main question is then, how can we differentiate/identify calls in an interceptor and run different logic for them without "hardcoding" it specifically, or is there any way to omit the interceptor for a specified call? Thank you in advance.
拦截器的代码可能有助于理解这个问题:
The code for an interceptor might help to understand the question:
Axios.interceptors.response.use(response => response, error => {
const status = error.response ? error.response.status : null
if (status === 401) {
// will loop if refreshToken returns 401
return refreshToken(store).then(_ => {
error.config.headers['Authorization'] = 'Bearer ' + store.state.auth.token;
error.config.baseURL = undefined;
return Axios.request(error.config);
})
// Would be nice to catch an error here, which would work if the interceptor is omitted
.catch(err => err);
}
return Promise.reject(error);
});
和令牌刷新部分:
function refreshToken(store) {
if (store.state.auth.isRefreshing) {
return store.state.auth.refreshingCall;
}
store.commit('auth/setRefreshingState', true);
const refreshingCall = Axios.get('get token').then(({ data: { token } }) => {
store.commit('auth/setToken', token)
store.commit('auth/setRefreshingState', false);
store.commit('auth/setRefreshingCall', undefined);
return Promise.resolve(true);
});
store.commit('auth/setRefreshingCall', refreshingCall);
return refreshingCall;
}
推荐答案
我可能找到了一种更简单的方法来处理这个问题:当我调用/api/时使用 axios.interceptors.response.eject() 来禁用拦截器refresh_token 端点,并在之后重新启用它.
I may have found a way much simpler to handle this : use axios.interceptors.response.eject() to disable the interceptor when I call the /api/refresh_token endpoint, and re-enable it after.
代码:
createAxiosResponseInterceptor() {
const interceptor = axios.interceptors.response.use(
response => response,
error => {
// Reject promise if usual error
if (error.response.status !== 401) {
return Promise.reject(error);
}
/*
* When response code is 401, try to refresh the token.
* Eject the interceptor so it doesn't loop in case
* token refresh causes the 401 response
*/
axios.interceptors.response.eject(interceptor);
return axios.post('/api/refresh_token', {
'refresh_token': this._getToken('refresh_token')
}).then(response => {
saveToken();
error.response.config.headers['Authorization'] = 'Bearer ' + response.data.access_token;
return axios(error.response.config);
}).catch(error => {
destroyToken();
this.router.push('/login');
return Promise.reject(error);
}).finally(createAxiosResponseInterceptor);
}
);
}
这篇关于通过 axios 中的拦截器自动刷新访问令牌的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!