如何让Angular拦截器等待Token就绪后处理后续请求?
解决方案
核心问题分析
你的问题根源有两个:
- 拦截器中直接使用
subscribe处理isTokenExist(),导致主线程直接返回未携带Token的请求,没有等待Token获取完成 AuthService.isTokenExist()的else分支错误地订阅了getToken(),而非返回其Observable,导致首次加载时无法正确等待Token获取
步骤1:修复AuthService的isTokenExist方法
修改isTokenExist(),确保所有路径都返回Observable,避免内部订阅导致的异步问题:
isTokenExist(): Observable<string | null> { const tokenTime = localStorage.getItem('token_time'); const currentToken = localStorage.getItem('token_'); // 与setToken中的存储key保持一致 if (tokenTime) { const currentTime = new Date().getTime(); const tokenTimeInt = parseInt(tokenTime, 10); // 判断Token是否过期,注意此处24小时的阈值需与实际Token有效期匹配 if (currentTime - tokenTimeInt > 86400000) { return this.getToken(); } else { return of(currentToken); } } else { // 直接返回getToken的Observable,而非内部订阅 return this.getToken(); } }
同时确认setToken的存储key一致性:
setToken(token: string): void { localStorage.setItem('token_', token); localStorage.setItem('token_time', new Date().getTime().toString()); }
步骤2:修复TokenInterceptor的拦截逻辑
将拦截器中的订阅改为Observable管道操作,确保请求等待Token就绪后再执行:
@Injectable() export class TokenInterceptor implements HttpInterceptor { constructor(private authService: AuthService) {} intercept(request: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> { // 跳过Token请求本身 if (request.url.includes('/connect/token?grant_type=client_credentials')) { return next.handle(request); } // 使用管道操作串联Token获取与请求处理 return this.authService.isTokenExist().pipe( catchError(error => { console.error('Token获取失败:', error); throw error; }), switchMap(token => { let modifiedRequest = request; if (token) { // 克隆请求并附加Authorization头 modifiedRequest = request.clone({ setHeaders: { Authorization: `Bearer ${token}`, }, }); } return next.handle(modifiedRequest); }) ); } }
关键改动说明
- 拦截器通过
switchMap操作符将Token获取的Observable与请求处理Observable串联,确保请求等待Token就绪后再执行 isTokenExist()统一返回Observable,无论Token是否存在/过期,都能让拦截器正确等待异步操作完成- 修正了
localStorage中Token存储与读取的key一致性问题
内容的提问来源于stack exchange,提问作者Vladyn
相关产品推荐
相关产品推荐

