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

Angular拦截器多请求顺序测试异常问题排查

Why Your Multiple Requests Test Shows Unexpected Order

Let's break down why your test is failing and what's happening under the hood:

The Root Cause of the Order Mismatch

Your interceptor's logic creates a subtle execution order issue when multiple requests hit a token refresh at the same time:

  1. First request (req1) triggers refresh: When req1 enters the interceptor, isRefreshing is false, so it kicks off the refreshToken call and waits for it to complete.
  2. Subsequent requests (req2, req3) wait on the subject: While refreshToken is delayed (1 second in your test), req2 and req3 come in. Since isRefreshing is now true, they subscribe to refreshTokenSubject and hold on for the new token.
  3. Token refresh completes, triggering subscribers first: When refreshToken finally resolves, the code runs:
    • this.refreshTokenSubject.next(token): This is a synchronous operation that immediately triggers all active subscribers (req2 and req3). Their next.handle() calls fire right away.
    • Only after that does the code execute return next.handle(request) for req1.

This is why your test sees the order req2 → req3 → req1 instead of your expected req1 → req2 → req3.

Why It Seems to Work in the Real World

In your actual web interface, requests are rarely fired synchronously one after another like in your test. There's usually natural delay between user actions or API triggers, so you never hit the scenario where three requests are all waiting on a token refresh at the same time. The order issue only surfaces in your controlled test environment.

How to Fix It

You have two options depending on your goal:

1. Fix the Interceptor to Preserve Request Order

If you want the interceptor to guarantee that requests are processed in the order they were triggered, adjust the logic to have all requests (including the first one) wait on the refreshTokenSubject:

private handleTokenRefresh(request: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
  if (!this.isRefreshing) {
    this.isRefreshing = true;
    this.refreshTokenSubject.next(null);
    // Fire off the refresh token call and update the subject when done
    this.jwtService.refreshToken().pipe(
      finalize(() => this.isRefreshing = false),
      catchError(err => {
        this.isRefreshing = false;
        return throwError(() => err);
      })
    ).subscribe(token => {
      this.refreshTokenSubject.next(token);
    });
  }
  // All requests wait on the subject, so they execute in subscription order
  return this.refreshTokenSubject.pipe(
    filter(token => token !== null),
    take(1),
    switchMap(jwt => next.handle(request))
  );
}

With this change, req1 will subscribe to the subject first, then req2, then req3. When the token is emitted, the subject will notify subscribers in the order they subscribed, preserving your desired execution sequence.

2. Adjust the Test to Match Current Interceptor Behavior

If you don't need to preserve request order and just want the test to pass, update your assertions to match the actual execution order:

expect(httpHandlerSpy.handle.calls.argsFor(0)).toEqual([httpRequestMock2]);
expect(httpHandlerSpy.handle.calls.argsFor(1)).toEqual([httpRequestMock3]);
expect(httpHandlerSpy.handle.calls.argsFor(2)).toEqual([httpRequestMock1]);

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.14 07:59:00