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

Angular拦截器与模块异常:懒加载模块拦截器误拦截登录请求

问题根源

Angular的HTTP拦截器是全局生效的——只要包含拦截器的模块被加载(哪怕是懒加载模块),拦截器就会加入全局的HTTP拦截器链,之后所有的HTTP请求都会经过它处理,不管请求来自主模块还是其他模块。你的Dashboard模块虽然是懒加载,但用户登录后进入过仪表盘,模块就会被加载,此时拦截器就会开始作用于所有请求,包括后续的登录请求(比如用户退出后重新登录的情况)。

解决方案

方案1:在拦截器中排除登录请求

最直接的方式是在拦截器里判断请求URL,跳过登录接口的错误处理逻辑,甚至跳过Token添加逻辑(如果登录接口不需要Token)。

修改token.interceptor.ts:

import { Injectable } from "@angular/core";
import {
  HttpRequest,
  HttpHandler,
  HttpEvent,
  HttpInterceptor,
  HttpErrorResponse,
} from "@angular/common/http";
import { Observable, catchError, throwError } from "rxjs";
import { AuthService } from "../services/auth.service";
import { ToastrService } from "ngx-toastr";
import { Router } from "@angular/router";

@Injectable()
export class TokenInterceptor implements HttpInterceptor {
  // 定义登录接口的路径,根据实际情况修改
  private loginEndpoint = '/api/auth/login';

  constructor(
    private auth: AuthService,
    private toastr: ToastrService,
    private router: Router
  ) {}

  intercept(
    request: HttpRequest<unknown>,
    next: HttpHandler
  ): Observable<HttpEvent<unknown>> {
    const token = this.auth.accessToken;

    // 只有非登录请求才添加Token头
    if (!!token && !request.url.includes(this.loginEndpoint)) {
      request = request.clone({
        setHeaders: { Authorization: `Bearer ${token}` },
      });
    }

    return next.handle(request).pipe(
      catchError((err: any) => {
        if (err instanceof HttpErrorResponse) {
          // 跳过登录请求的401错误处理
          if (err.status === 401 && !request.url.includes(this.loginEndpoint)) {
            this.toastr.warning(
              "请重新登录",
              "会话已过期"
            );
            this.router.navigate(["login"]);
          }
        }
        return throwError(() => err);
      })
    );
  }
}

方案2:将拦截器移到主模块,优化逻辑

把拦截器配置到app.module.ts的providers中,同时保持逻辑里的条件判断——只有存在Token时才添加请求头,并且区分登录请求的401:

  1. 修改app.module.ts的providers:
providers: [
  {
    provide: HTTP_INTERCEPTORS,
    useClass: TokenInterceptor,
    multi: true,
  },
],
  1. 移除dashboard.module.ts中拦截器的配置。

  2. 拦截器的逻辑和方案1一致,保留对登录请求的排除。

这种方式更符合Angular拦截器的全局设计思路,同时通过条件判断实现差异化处理。

方案3:拆分拦截器(可选)

如果逻辑复杂,可以拆分成两个拦截器:一个负责给请求添加Token,另一个负责处理401错误,在错误处理拦截器里排除登录请求。

  • Token添加拦截器:只处理Token注入,不处理错误。
  • 错误处理拦截器:只处理非登录请求的401错误。

这种方式让职责更清晰,适合大型项目。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.23 12:12:02