Angular HTTP拦截器调用服务时失效问题求助
Angular HTTP拦截器调用AuthService获取Token时无后续逻辑问题
我创建了HTTP拦截器,用来自动给所有HTTP请求添加请求头,无需手动配置每个请求。但在拦截器内调用GoogleAuthService获取token时,拦截器仅打印初始日志Interceptor: Intercepting request...,无法进入服务调用后的逻辑;而硬编码token时,拦截器可正常工作。
拦截器文件
import { Injectable } from '@angular/core'; import { HttpRequest, HttpHandler, HttpEvent, HttpInterceptor } from '@angular/common/http'; import { Observable, from } from 'rxjs'; import { switchMap } from 'rxjs/operators'; import { GoogleAuthService } from './services/auth/auth.service'; @Injectable() export class AuthInterceptor implements HttpInterceptor { constructor(private authService: GoogleAuthService) { } intercept(request: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> { console.log('Interceptor: Intercepting request...'); return this.authService.requestToken().pipe( switchMap(token => { console.log('Interceptor: Token obtained -', token); const authRequest = this.addAuthenticationToken(request, token); return next.handle(authRequest); }) ); } addAuthenticationToken(request: HttpRequest<any>, token: string) { return request.clone({ setHeaders: { Authorization: `Bearer ${token}` } }); } }
服务文件
该函数调用GCP云函数获取token,供拦截器使用:
import { Injectable, SkipSelf } from '@angular/core'; import { HttpClient, HttpHeaders } from '@angular/common/http'; import { Observable, catchError, throwError } from 'rxjs'; @Injectable({ providedIn: 'root' }) export class GoogleAuthService { audience = 'https://cloud.run.app'; constructor(private http: HttpClient) {} requestToken(): Observable<any> { const requestUrl = "https://us-central1-gcp.cloudfunctions.net/get-token" const tokenUrl = `${requestUrl}?url=${this.audience}` return this.http.get(tokenUrl) } }
模块文件
import { NgModule } from '@angular/core'; import { BrowserModule } from '@angular/platform-browser'; import { HttpClientModule, HTTP_INTERCEPTORS } from '@angular/common/http'; import { AppRoutingModule } from './app-routing.module'; import { AppComponent } from './app.component'; import { GoogleAuthService } from './services/auth/auth.service'; import { AuthInterceptor } from './auth.interceptor'; @NgModule({ declarations: [ AppComponent ], imports: [ BrowserModule, AppRoutingModule, HttpClientModule ], providers: [ { provide: HTTP_INTERCEPTORS, useClass: AuthInterceptor, multi: true, deps: [GoogleAuthService] } ], bootstrap: [AppComponent] }) export class AppModule { }
浏览器请求状态截图

问题根源
这是循环依赖死锁导致的:
- 拦截器依赖GoogleAuthService,而GoogleAuthService又依赖HttpClient
- HttpClient初始化时会触发所有HTTP_INTERCEPTORS的初始化,进而回到拦截器,形成闭环,导致
requestToken()的调用永远无法完成
解决方案
方案1:标记并跳过Token请求的拦截
修改GoogleAuthService的requestToken()方法,添加自定义请求头,让拦截器跳过该请求:
requestToken(): Observable<any> { const requestUrl = "https://us-central1-gcp.cloudfunctions.net/get-token" const tokenUrl = `${requestUrl}?url=${this.audience}` // 添加自定义头,告知拦截器跳过当前请求 return this.http.get(tokenUrl, { headers: new HttpHeaders({ 'skipInterceptor': 'true' }) }) }
然后在拦截器的intercept方法开头增加判断逻辑:
intercept(request: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> { // 跳过获取Token的请求,避免循环依赖 if (request.headers.has('skipInterceptor')) { // 删除自定义头后继续请求,避免传递到后端 return next.handle(request.clone({ headers: request.headers.delete('skipInterceptor') })); } console.log('Interceptor: Intercepting request...'); return this.authService.requestToken().pipe( switchMap(token => { console.log('Interceptor: Token obtained -', token); const authRequest = this.addAuthenticationToken(request, token); return next.handle(authRequest); }) ); }
方案2:直接使用HttpClientBackend绕开拦截器
在GoogleAuthService中注入HttpClientBackend,直接发起请求,完全绕开拦截器链:
import { Injectable } from '@angular/core'; import { HttpClientBackend, HttpRequest, HttpResponse } from '@angular/common/http'; import { Observable, catchError, throwError } from 'rxjs'; @Injectable({ providedIn: 'root' }) export class GoogleAuthService { audience = 'https://cloud.run.app'; constructor(private httpBackend: HttpClientBackend) {} requestToken(): Observable<any> { const requestUrl = "https://us-central1-gcp.cloudfunctions.net/get-token" const tokenUrl = `${requestUrl}?url=${this.audience}` const request = new HttpRequest('GET', tokenUrl); return new Observable(observer => { this.httpBackend.handle(request).subscribe({ next: (event) => { if (event instanceof HttpResponse) { observer.next(event.body); observer.complete(); } }, error: (err) => { observer.error(err); } }); }).pipe(catchError(err => throwError(() => err))); } }
额外优化建议
给requestToken()添加错误处理,避免Token请求失败导致所有业务请求阻塞:
requestToken(): Observable<any> { const requestUrl = "https://us-central1-gcp.cloudfunctions.net/get-token" const tokenUrl = `${requestUrl}?url=${this.audience}` return this.http.get(tokenUrl, { headers: new HttpHeaders({ 'skipInterceptor': 'true' }) }).pipe( catchError(err => { console.error('获取Token失败:', err); return throwError(() => err); }) ); }
内容的提问来源于stack exchange,提问作者Umamaheswararao Meka
相关产品推荐
相关产品推荐

