我正在使用该示例,https://www.thedutchlab.com/insights/using-axios-interceptors-for-refreshing-your-api-token,在React中的JWT应用程序中实现刷新令牌的使用.
但是,如果由于任何原因使用刷新令牌失败,则上面链接中提供的代码不会处理此类错误。在 React 中,它会导致未捕获的错误屏幕。
我寻找了使用刷新令牌的其他类似示例。它们看起来都一样,并且此类故障未得到处理。我应该如何在代码中处理该问题以将用户重定向到登录页面而不显示未捕获的错误?
这是我的代码:
import axios from "axios";
import TokenService from "./token";
const instance = axios.create({
baseURL: process.env.REACT_APP_BACKEND_API_URL,
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json',
},
timeout: 5000
});
instance.interceptors.request.use(
(config) => {
const token = TokenService.getLocalAccessToken();
if (token) {
config.headers['Authorization'] = 'Bearer ' + token;
}
return config;
},
(error) => {
return Promise.reject(error);
}
);
instance.interceptors.response.use(
(res) => {
return res;
},
async (err) => {
const originalConfig = err.config;
if (originalConfig.url !== "/login" && err.response) {
if (err.response.status === 401 && !originalConfig.retry) {
originalConfig.retry = true;
try {
const response = await instance.post("/refreshtoken", {
"@ObjectType": "RefreshToken#1.0.0",
RefreshToken: TokenService.getLocalRefreshToken(),
});
TokenService.updateLocalAccessToken(response.data.Token);
TokenService.updateLocalRefreshToken(response.data.RefreshToken);
return instance(originalConfig);
} catch (error) {
TokenService.removeUser();
window.location.replace(process.env.REACT_APP_FRONTEND_URL + '/#/login');
}
}
}
return Promise.reject(err);
}
);
export default instance;
问题是,即使脚本重定向到登录页面(如
window.location.replace(process.env.REACT_APP_FRONTEND_URL + '/#/login')
行中所示),未捕获的错误也会显示在屏幕上,如下所示:
这是我的方法,重定向到登录屏幕不是直接操作,而是丢失会话的结果:
// * when the AT is expired, so we need to get a new one (refresh)
const newAccessToken = await refresh();
// if the RT is expired, we won't find any AT, an this case a simple refresh (reload) must be enough to lose the session and get back to the login/home screen
if(!newAccessToken){
window.location.reload();
}
// * Normal process of attaching new AT and attaching it to interceptors
prevRequest.headers['Authorization'] = `Bearer ${newAccessToken}`;
我总是使用类似于以下的代码来完成此操作,这些代码可以转换为您首选的 API 请求编码方式,例如拦截器:
private async callApi(path: string, method: Method, dataToSend?: any): Promise<any> {
// Get the full path
const url = `${this._apiBaseUrl}${path}`;
// Get the access token, and if it does not exist a login redirect will be triggered
let token = await this._authenticator.getAccessToken();
try {
// Call the API
return await this._callApiWithToken(url, method, dataToSend, token);
} catch (e: any) {
// Report Ajax errors if this is not a 401
if (e.statusCode !== 401) {
throw e;
}
// If we received a 401 then try to refresh the access token
token = await this._authenticator.refreshAccessToken();
// The general pattern for calling an OAuth secured API is to retry 401s once with a new token
return await this._callApiWithToken(url, method, dataToSend, token);
}
}
如果还没有访问令牌,或者令牌刷新失败并出现
invalid_grant
错误代码,我会抛出 LoginRequired 异常。此错误由错误呈现代码专门处理,避免渲染它。
然后要求用户重新进行身份验证,例如通过更新
location.href
,并且用户不会遇到任何错误。建议排练此到期事件,例如。通过将字符附加到刷新令牌来导致此错误响应。
我更喜欢使用服务代理类的方法来封装响应缓存、自定义标头和重试等管道。不过,有些人更喜欢拦截器方法。