You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何静默刷新认证Token并重发HttpRequest请求

Angular 4+ 拦截器401重试:Token刷新后重发请求

解决你的两个核心问题


1. 为什么示例不用subscribe就能触发请求?

Angular的HttpClient在发起请求时,会自动订阅你从intercept方法返回的Observable。你在refreshToken()里手动调用subscribe(),虽然能触发Token刷新请求,但会打破拦截器的链式流——返回的Observable已经被提前订阅,拦截器无法利用这个流完成后续的请求重发操作。

2. 用什么操作器重发请求?

用switchMap操作符最合适:它会等待Token刷新的Observable完成,然后切换到重发请求的Observable。tap仅用于执行副作用(比如打印日志),不会改变流的内容;mergeMap也能实现,但switchMap可以避免同时触发多个Token刷新请求(如果有多个401请求同时进来,只会保留最后一个刷新操作)。


修正后的完整代码

1. 改造AuthenticationService的refreshToken方法

去掉手动subscribe,把存Cookie的逻辑放到tap里,保持流的链式传递:

refreshToken(): Observable<KeyCloakToken> {
  return this.http.post<KeyCloakToken>(`${this.authUrl}/auth/refresh`, { refreshToken: this.refreshToken })
    .pipe(
      tap(data => {
        console.log("tap in refreshToken", data);
        this.saveCookie(data); // 存Cookie的逻辑放到tap中,无需手动订阅
      })
    );
}

2. 完善AuthInterceptor的拦截逻辑

在catchError中连接Token刷新流和请求重发流,同时处理刷新失败的情况:

@Injectable()
export class AuthInterceptor implements HttpInterceptor {
  constructor(private auth: AuthenticationService) {}

  intercept(request: HttpRequest<unknown>, next: HttpHandler): Observable<HttpEvent<unknown>> {
    // 先添加初始认证头
    let authRequest = this.addAuthHeader(request);

    return next.handle(authRequest).pipe(
      catchError((error: any) => {
        // 仅处理401的HTTP错误
        if (error instanceof HttpErrorResponse && error.status === 401) {
          // 刷新Token后重发请求
          return this.auth.refreshToken().pipe(
            switchMap(() => {
              // Token刷新完成后,重新构建带新Token的请求
              const newAuthRequest = this.addAuthHeader(request);
              // 重发原请求
              return next.handle(newAuthRequest);
            }),
            // 处理Token刷新失败的情况(比如跳转到登录页)
            catchError(refreshError => {
              console.error("Token刷新失败", refreshError);
              // 这里可以添加跳转到登录页的逻辑,比如:this.router.navigate(['/login'])
              return throwError(() => refreshError);
            })
          );
        }
        // 非401错误,直接抛出原错误
        return throwError(() => error);
      })
    );
  }

  // 封装添加认证头的方法
  private addAuthHeader(request: HttpRequest<unknown>): HttpRequest<unknown> {
    const token = this.auth.getToken(); // 假设你有获取最新Token的方法
    if (token) {
      return request.clone({
        setHeaders: {
          Authorization: `Bearer ${token}`
        }
      });
    }
    return request;
  }
}

内容的提问来源于stack exchange,提问作者tung

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.29 19:23:28