我有这个拦截器代码,用于使用Axios发出的所有请求。这里的instance
是Axios示例。
instance.interceptors.request.use(async (config) => {
const tokens = JSON.parse(localStorage.getItem('users'));
if (!tokens) {
return config;
}
const accessTokenValid = Date.now() <= (tokens?.expirationTime ?? Date.now());
if (accessTokenValid) {
return config;
}
const refreshToken = tokens.refreshToken;
if (!refreshToken) {
return config;
}
const response = await fetch(`${some-endpoint}/auth/refresh/token?token=${refreshToken}`);
const newTokens = (await response.json()).data.data;
localStorage.setItem('users', JSON.stringify(
{
accessToken: newTokens.access_token,
expirationTime: Date.now() + parseInt(JSON.parse(newTokens.expires_in)) * 1000 - 600 * 1000,
refreshToken: newTokens.refresh_token,
}
));
config.headers.Authorization = `Bearer ${newTokens.access_token}`;
return config;
}, (error) => {
console.error(error);
});
然后,instance
将像这样使用。
return instance.get(
"/users/" + id,
options
);
options
是这样的
{
headers: {
Authorization: `Bearer ${session.accessToken}`,
},
}
上面代码的问题是令牌过期后的第一个请求总是失败。然后,localStorage.users
中的值将被更新,并且第二个请求将成功,因为该值已被新的访问令牌替换。
我不想在响应中使用拦截器来重试原始请求。我想根据请求处理令牌刷新。经过调查,发现HTTP请求发生的顺序如下所示。
- 对端点
users
的HTTP请求 - 然后,向端点发送HTTP请求以刷新令牌
这告诉我请求拦截器中的async/await
部分没有工作。我怎样才能使HTTP请求在运行HTTP请求本身之前必须等待拦截器首先完成运行(包括等待任何异步函数)?
2条答案
按热度按时间gwbalxhn1#
在这里我会做一些不同的事情...
1.* 始终 * 将添加
Authorization
头的责任委托给拦截器。您的消费代码不需要知道它1.对需要令牌刷新的请求进行排队,以避免多次刷新请求
1.对所有请求使用Fetch或Axios。混合它们只会导致更大的爆炸半径和更困难的测试
您可以看到,序列首先解析刷新令牌,并且在使用更新的访问令牌发出 user 请求之前只解析一次。
cld4siwp2#
这里出现的问题是因为axios在拦截器有机会刷新令牌之前发送了原始请求。您需要做的是防止发送原始请求,直到令牌被刷新。
一种方法是显式地暂停原始请求,直到刷新完成。这可以通过在刷新令牌时创建传入请求的队列,然后在刷新令牌后解析它们来完成。