Angular 18中HttpInterceptorFn使用localStorage报错的解决方法
Angular HttpInterceptorFn中使用localStorage导致页面渲染超时的解决方法
我是Angular新手,在HttpInterceptorFn中调用localStorage.getItem()获取access和refresh令牌时,页面出现错误:Page /admin did not render in 30 seconds.,移除localStorage.getItem()代码后错误消失。相关代码如下:
auth.interceptor.ts
import { HttpInterceptorFn } from '@angular/common/http'; export const authInterceptor: HttpInterceptorFn = (req, next) => { const accessToken = localStorage.getItem('access'); const refreshToken = localStorage.getItem('refresh'); return next(req); };
profile.component.ts
import { Component, OnInit } from '@angular/core'; import { UserService } from '../../services/user.service'; import { ActivatedRoute } from '@angular/router'; import { Title } from '@angular/platform-browser'; import { User } from '../../models/user'; @Component({ selector: 'app-profile', standalone: true, imports: [], templateUrl: './profile.component.html', styleUrl: './profile.component.scss' }) export class ProfileComponent implements OnInit { user: User | null = null; isFailed = false; constructor( private userService: UserService, private route: ActivatedRoute, private titleService: Title) { } ngOnInit(): void { this.route.paramMap.subscribe((paramMap) => { const username = String(paramMap.get('username')); this.userService.getUser(username).subscribe({ next: (user) => { this.isFailed = false; this.user = user; this.titleService.setTitle(`${this.user.display_name || this.user.username} profile`); }, error: () => { this.isFailed = true; } }); }); } }
问题原因
问题出在服务端渲染(SSR)环境不支持localStorage。Angular在SSR模式下会先在Node.js环境执行组件和拦截器代码,而localStorage是浏览器专属API,Node.js环境中不存在该对象,执行时会触发未捕获错误,导致页面渲染流程卡住,最终超时。
解决方案
核心思路是先判断当前是否处于浏览器环境,再调用localStorage,以下是两种可靠实现方式:
方法1:通过检查window对象判断环境
修改auth.interceptor.ts代码:
import { HttpInterceptorFn } from '@angular/common/http'; export const authInterceptor: HttpInterceptorFn = (req, next) => { let accessToken: string | null = null; let refreshToken: string | null = null; // 仅在浏览器环境下读取localStorage if (typeof window !== 'undefined') { accessToken = localStorage.getItem('access'); refreshToken = localStorage.getItem('refresh'); } // 可选:如果有accessToken,给请求添加Authorization头 if (accessToken) { req = req.clone({ setHeaders: { Authorization: `Bearer ${accessToken}` } }); } return next(req); };
方法2:使用Angular官方平台判断工具
这种方式更符合Angular最佳实践,通过PLATFORM_ID和isPlatformBrowser判断环境:
import { HttpInterceptorFn } from '@angular/common/http'; import { PLATFORM_ID, inject } from '@angular/core'; import { isPlatformBrowser } from '@angular/common'; export const authInterceptor: HttpInterceptorFn = (req, next) => { const platformId = inject(PLATFORM_ID); let accessToken: string | null = null; let refreshToken: string | null = null; if (isPlatformBrowser(platformId)) { accessToken = localStorage.getItem('access'); refreshToken = localStorage.getItem('refresh'); } // 可选:如果有accessToken,给请求添加Authorization头 if (accessToken) { req = req.clone({ setHeaders: { Authorization: `Bearer ${accessToken}` } }); } return next(req); };
内容的提问来源于stack exchange,提问作者Kirill
相关产品推荐
相关产品推荐

