Angular 20中使用DI-based拦截器时API无法执行,页面长时间加载无响应
看起来你碰到了Angular 20结合SSR(服务端渲染)使用DI式HTTP拦截器时的请求阻塞问题,我来帮你理清楚问题根源和解决办法:
先确认:你的基础代码逻辑是没问题的
先给你吃个定心丸——你写的TokenInterceptor、app.config.ts里的拦截器注册,还有ProductService的API调用代码本身都是正确的:
- 拦截器里注入
TokenService、克隆请求添加Authorization头的逻辑没问题 app.config.ts里正确启用了withInterceptorsFromDi(),也按要求注册了HTTP_INTERCEPTORS提供商- 产品服务里的参数拼接和HTTP请求写法也符合Angular规范
问题的核心:SSR环境的特殊限制
你提到项目用了SSR(从app.routes.server.ts的预渲染配置能看出来),这就是关键!在SSR场景中,服务端渲染阶段的代码是跑在Node.js环境里的,没有浏览器的localStorage/sessionStorage这些API——而你的TokenService大概率是从这些浏览器存储里获取token的,这就导致服务端执行拦截器逻辑时,要么获取token失败抛出错误,要么因为尝试访问不存在的浏览器API卡住,进而阻塞了整个API请求流程,最终页面就一直加载没响应。
验证结论:排除SSR就正常
你已经做了最关键的测试:新建一个没有SSR的Angular项目,用同样的拦截器和API代码就能正常工作,这直接坐实了问题出在SSR和拦截器的交互上。
具体修复方案
针对SSR环境,我们需要让拦截器和TokenService区分“服务端”和“浏览器”环境来执行逻辑:
1. 修改TokenInterceptor,仅在浏览器环境下添加token
注入PLATFORM_ID来判断当前运行环境,只在浏览器里执行添加token的逻辑:
import { HttpEvent, HttpHandler, HttpInterceptor, HttpRequest } from "@angular/common/http"; import { Injectable, Inject, PLATFORM_ID } from "@angular/core"; import { Observable } from "rxjs"; import { TokenService } from "../service/token.service"; import { isPlatformBrowser } from "@angular/common"; @Injectable() export class TokenInterceptor implements HttpInterceptor { constructor( private tokenService: TokenService, @Inject(PLATFORM_ID) private platformId: Object ) { } intercept( req: HttpRequest<any>, next: HttpHandler ): Observable<HttpEvent<any>> { // 仅在浏览器环境下尝试获取并添加token if (isPlatformBrowser(this.platformId)) { const token = this.tokenService.getToken(); if (token) { req = req.clone({ setHeaders: { Authorization: `Bearer ${token}`, } }); } } return next.handle(req); } }
2. 修复TokenService,避免服务端报错
确保TokenService在服务端环境下不会因为访问浏览器API报错:
import { Injectable } from '@angular/core'; @Injectable({ providedIn: 'root' }) export class TokenService { getToken(): string | null { // 服务端环境直接返回null,避免访问localStorage报错 if (typeof window === 'undefined') { return null; } return localStorage.getItem('token'); } }
3. 检查SSR服务端配置
确保你的SSR服务端代码(比如main.server.ts)里的HTTP客户端初始化也正确支持DI拦截器,避免服务端请求时出现死锁或未处理的Promise。
总结
你的代码在纯浏览器环境下完全正常,问题就是SSR场景中服务端无法处理浏览器特有的存储API,导致拦截器逻辑阻塞了请求。通过区分平台环境调整拦截器和TokenService的逻辑,就能解决页面长时间加载无响应的问题。
内容来源于stack exchange

