Angular中用Refresh Token获取新Token后无法重发原请求问题
问题分析
当前错误拦截器捕获401并刷新token后,仅更新了localStorage中的token,但未重新发起原请求,而是直接返回错误,导致前端仍接收到401响应。必须手动刷新页面让jwtInterceptor重新读取新token,该逻辑存在明显缺陷。
修正方案
1. 改造AuthService的refreshAccessToken方法
将回调模式改为返回Promise,方便拦截器等待token刷新完成:
@Injectable({ providedIn: 'root' }) export class AuthService { constructor( private httpClient: HttpClientService, private jwtHelper: JwtHelperService, private router: Router ) {} async refreshAccessToken(): Promise<boolean> { const refreshToken = localStorage.getItem('refreshToken'); if (!refreshToken) return false; const response$ = this.httpClient.post({ controller: "auth", action: "LoginRefreshToken", }, { refreshToken }); try { const tokens: TokenResponse = await firstValueFrom(response$) as TokenResponse; if (tokens) { localStorage.setItem('accessToken', tokens.accessToken); localStorage.setItem('refreshToken', tokens.refreshToken); return true; } return false; } catch { return false; } } addJwtBearer(req: HttpRequest<unknown>): HttpRequest<unknown> { let authToken = localStorage.getItem("accessToken"); const apiUrl = req.url.startsWith("https://localhost:7096/api"); if (authToken && apiUrl) { return req.clone({ setHeaders: { Authorization: `Bearer ${authToken}` } }); } return req; } logOut() { localStorage.removeItem('accessToken'); localStorage.removeItem('refreshToken'); this.router.navigate(["/"]); } }
2. 修改错误拦截器,实现请求重发
捕获401后,等待token刷新成功,克隆原请求并添加新token重新发起:
export const errorHandlerInterceptor: HttpInterceptorFn = (req, next) => { const alertifyService = inject(AlertifyService); const router = inject(Router); const authService = inject(AuthService); return next(req).pipe( catchError(async (err) => { if (err.status === 401) { const hasTokens = !!localStorage.getItem('accessToken') && !!localStorage.getItem('refreshToken'); if (hasTokens) { const refreshSuccess = await authService.refreshAccessToken(); if (refreshSuccess) { const newReq = authService.addJwtBearer(req); return next(newReq); } else { authService.logOut(); } } else { alertifyService.message("Yetkisiz erişim!!", { messageType: MessageType.Error, position: SetPosition.TopRight }); router.navigate(["/"]); } } return throwError(() => err); }) ); };
3. 确保拦截器顺序正确
在provideHttpClient配置中,jwtInterceptor必须在errorHandlerInterceptor之前,保证重发的请求能先带上新token:
// app.config.ts 或相关配置文件 export const appConfig: ApplicationConfig = { providers: [ provideHttpClient(withInterceptors([jwtInterceptor, errorHandlerInterceptor])), // 其他服务提供者... ] };
关键说明
- 刷新token后必须重新发起原请求,确保新token被注入请求头
- 用Promise/async-await处理异步刷新逻辑,避免回调导致的时序混乱
- 拦截器顺序直接影响重发请求的token注入逻辑,不可颠倒
内容的提问来源于stack exchange,提问作者serhat başoğlu
相关产品推荐
相关产品推荐

