我正在我的web应用程序中实现令牌身份验证。我的access token每隔N分钟过期一次,然后使用refresh token登录并获取新的access token。
我所有的API调用都使用Axios。我设置了一个拦截器来拦截401响应。
axios.interceptors.response.use(undefined, function (err) {
if (err.status === 401 && err.config && !err.config.__isRetryRequest) {
serviceRefreshLogin(
getRefreshToken(),
success => { setTokens(success.access_token, success.refresh_token) },
error => { console.log('Refresh login error: ', error) }
)
err.config.__isRetryRequest = true
err.config.headers.Authorization = 'Bearer ' + getAccessToken()
return axios(err.config);
}
throw err
})基本上,当我截获401响应时,我希望进行登录,然后使用新令牌重试最初被拒绝的请求。我的serviceRefreshLogin函数在其then块中调用setAccessToken()。但问题是,在拦截器中,then阻塞发生的时间晚于getAccessToken(),因此重试是使用旧的过期凭据进行的。
getAccessToken()和getRefreshToken()只是返回存储在浏览器中的现有令牌(它们管理localStorage、cookies等)。
我该如何确保语句在promise返回之前不会执行?
(在github上有一个相应的问题:https://github.com/mzabriskie/axios/issues/266)
发布于 2016-03-19 00:06:50
只需使用另一个承诺:D
axios.interceptors.response.use(undefined, function (err) {
return new Promise(function (resolve, reject) {
if (err.status === 401 && err.config && !err.config.__isRetryRequest) {
serviceRefreshLogin(
getRefreshToken(),
success => {
setTokens(success.access_token, success.refresh_token)
err.config.__isRetryRequest = true
err.config.headers.Authorization = 'Bearer ' + getAccessToken();
axios(err.config).then(resolve, reject);
},
error => {
console.log('Refresh login error: ', error);
reject(error);
}
);
}
throw err;
});
});如果您环境不支持promises,请使用polyfill,例如https://github.com/stefanpenner/es6-promise
但是,重写getRefreshToken以返回promise,然后使代码更简单可能会更好
axios.interceptors.response.use(undefined, function (err) {
if (err.status === 401 && err.config && !err.config.__isRetryRequest) {
return getRefreshToken()
.then(function (success) {
setTokens(success.access_token, success.refresh_token) ;
err.config.__isRetryRequest = true;
err.config.headers.Authorization = 'Bearer ' + getAccessToken();
return axios(err.config);
})
.catch(function (error) {
console.log('Refresh login error: ', error);
throw error;
});
}
throw err;
});发布于 2018-04-12 10:16:23
可以在请求中这样做,而不是在响应中,而且可能会更干净,因为它可以避免在访问令牌过期时访问服务器。从this article复制
function issueToken() {
return new Promise((resolve, reject) => {
return client({
...
}).then((response) => {
resolve(response);
}).catch((err) => {
reject(err);
});
});
}
client.interceptors.request.use((config) => {
let originalRequest = config;
if (tokenIsExpired && path_is_not_login) {
return issueToken().then((token) => {
originalRequest['Authorization'] = 'Bearer ' + token;
return Promise.resolve(originalRequest);
});
}
return config;
}, (err) => {
return Promise.reject(err);
});
https://stackoverflow.com/questions/35900230
复制相似问题