Angular HTTP拦截器如何等待Token获取完成再执行?
解决Angular HTTP拦截器等待Token获取完成的方案
核心问题在于你之前的代码把异步的Token获取逻辑当成同步处理了,apiLogin返回的是Observable,异步操作不会阻塞后续代码执行,导致请求先发送了,Token还没拿到。需要把整个Token获取流程改成异步Observable流,让拦截器等待Token就绪后再处理请求。
步骤1:重构Token获取方法为异步Observable
修改getApiToken,让它返回Observable<string>,不再直接返回字符串:
getApiToken(): Observable<string> { let token = <string>sessionStorage.getItem('auth-token'); // 检查Token是否存在且有效 if (token && !this.jwt.isTokenExpired(token)) { return of(token); } // Token无效或不存在,调用登录接口获取新Token return this.apiLogin().pipe( tap(data => { sessionStorage.setItem("auth-token", data.token); }), map(data => data.token), catchError(err => { console.log(err); return of(''); }) ); }
步骤2:修改URL检查方法返回Observable
修改checkUrl,让它返回Observable<string>,对应需要授权的接口返回Token的Observable,不需要的返回空字符串的Observable:
checkUrl(url: string): Observable<string> { if (url.includes('/login')) { return of(''); } // 检查是否在需要授权的列表里 const needsAuth = this.includedList.some(item => url.includes(item.url)); if (needsAuth) { return this.auth.getApiToken(); } return of(''); }
步骤3:重构拦截器逻辑,等待Token就绪
拦截器需要先订阅Token的Observable,拿到Token后再克隆请求并发送,这里用switchMap操作符来串联异步流:
intercept(request: HttpRequest<unknown>, next: HttpHandler): Observable<HttpEvent<unknown>> { // 先检查当前请求是否需要授权并获取Token return this.checkUrl(request.url).pipe( switchMap(token => { let authReq = request; if (token) { // 克隆请求并添加Auth头 authReq = request.clone({ headers: request.headers.set(this.TOKEN_HEADER_KEY, 'Bearer ' + token) }); } // 发送处理后的请求 return next.handle(authReq); }) ); }
关键说明
- 所有涉及Token获取的方法都改为返回Observable,这样可以利用RxJS的操作符处理异步流
- 拦截器不再同步获取Token,而是通过
switchMap等待Token的Observable发出值后,再处理请求 - 使用
tap操作符处理Token的存储(只做副作用,不改变流的值),map用来转换登录接口返回的数据为Token字符串,catchError处理登录失败的情况
这样修改后,拦截器会等待Token获取完成(不管是从缓存取还是从接口请求),再添加Auth头发送请求,解决了异步导致的Token未就绪问题。
内容的提问来源于stack exchange,提问作者BeRightBack
相关产品推荐
相关产品推荐

