Angular拦截器调用JWT刷新API触发无限循环问题排查
问题原因及解决方法
无限循环的核心原因是:刷新令牌的请求也会被你的拦截器捕获。因为refreshToken请求的URL符合isApiUrl的判断条件,而此时旧的access token已经过期,拦截器会再次触发令牌刷新逻辑,形成无限递归。
解决步骤
1. 让刷新令牌请求跳过拦截器处理
你需要给刷新请求添加一个“豁免标识”,让拦截器识别并直接放行,不执行认证逻辑。有两种常用方式:
方式一:通过请求URL判断
在拦截器最开头,先检查当前请求是否是刷新令牌的接口,如果是直接放行:
intercept(request: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> { // 先判断是否是刷新令牌请求,直接放行 const isRefreshTokenRequest = request.url.includes('/authentication/refresh-token'); if (isRefreshTokenRequest) { return next.handle(request); } // 以下是原来的认证逻辑 const token = this.localStorageService.token; const isApiUrl = request.url.startsWith(environment.apiUrl); if (token && isApiUrl) { if (this.jwtHelperService.isTokenExpired(token)) { return from(this.refreshToken()).pipe(mergeMap((response) => { if (response) { localStorage.setItem(LocalStorageKeys.TOKEN, JSON.stringify(response)); request = request.clone({ setHeaders: { Authorization: `Bearer ${response}` } }); return next.handle(request); } else { this.authenticationService.logout(); return next.handle(request); } })); } else { request = request.clone({ setHeaders: { Authorization: `Bearer ${token}` } }); return next.handle(request); } } return next.handle(request); }
方式二:通过自定义请求头判断
在refreshToken方法的请求中添加自定义头,然后拦截器检查这个头并放行:
修改refreshToken方法:
async refreshToken(): Promise<string> { const res$ = this.http .post(`${environment.apiUrl}/authentication/refresh-token`, { token: this.localStorageService.token, refreshToken: this.localStorageService.refreshToken }, // 添加自定义请求头标识 { headers: new HttpHeaders({ 'Skip-Auth-Interceptor': 'true' }) }) .pipe(map((res) => res['data']['token'])) .pipe(first()); const response = await lastValueFrom(res$); return response; }
修改拦截器开头逻辑:
intercept(request: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> { // 检查是否有跳过拦截的标识 const skipAuthInterceptor = request.headers.has('Skip-Auth-Interceptor'); if (skipAuthInterceptor) { // 移除自定义头(可选,避免传给后端) const clonedRequest = request.clone({ headers: request.headers.delete('Skip-Auth-Interceptor') }); return next.handle(clonedRequest); } // 以下是原来的认证逻辑 }
2. 额外注意事项
- 确保后端的刷新令牌接口不需要携带有效的access token,仅需要refresh token即可完成验证,否则刷新请求会被后端拒绝。
- 建议在拦截器中添加“正在刷新令牌”的状态锁,避免同一时间多个过期请求触发多次刷新操作。
内容的提问来源于stack exchange,提问作者Pawan Nogariya
相关产品推荐
相关产品推荐

