Angular拦截器获取localStorage中accessToken始终为null求助
Angular拦截器JWT Token无法添加到请求头的解决方案
核心问题
拦截器在token完成存入localStorage之前就尝试读取它,导致Authorization请求头无法正确设置。
可行解决方法
1. 用BehaviorSubject实现token异步订阅
将AuthService中的token存储改为RxJS BehaviorSubject管理,让拦截器通过订阅流获取最新token,确保能拿到已存入的值:
// auth.service.ts import { Injectable } from '@angular/core'; import { BehaviorSubject } from 'rxjs'; @Injectable({ providedIn: 'root' }) export class AuthService { private tokenSubject = new BehaviorSubject<string | null>(localStorage.getItem('token')); public token$ = this.tokenSubject.asObservable(); setToken(token: string): void { localStorage.setItem('token', token); this.tokenSubject.next(token); // 更新流的最新值 } clearToken(): void { localStorage.removeItem('token'); this.tokenSubject.next(null); } }
拦截器中切换为异步获取token:
// auth.interceptor.ts import { Injectable } from '@angular/core'; import { HttpRequest, HttpHandler, HttpEvent, HttpInterceptor } from '@angular/common/http'; import { Observable, switchMap } from 'rxjs'; import { AuthService } from './auth.service'; @Injectable() export class AuthInterceptor implements HttpInterceptor { constructor(private authService: AuthService) {} intercept(request: HttpRequest<unknown>, next: HttpHandler): Observable<HttpEvent<unknown>> { return this.authService.token$.pipe( switchMap(token => { if (token) { request = request.clone({ setHeaders: { Authorization: `Bearer ${token}` } }); } return next.handle(request); }) ); } }
2. 确保登录后请求的执行时机
如果登录后立即跳转并发起请求,需保证在token存入localStorage之后再执行后续操作:
// login.component.ts login() { this.authService.login(this.loginForm.value).subscribe({ next: (response) => { this.authService.setToken(response.token); // 确保token存入后再跳转/发起请求 this.router.navigate(['/dashboard']); // 若需同步发起请求,直接在setToken后执行即可 // this.dashboardService.loadData().subscribe(...); } }); }
3. 检查拦截器配置顺序
确保拦截器在HttpClientModule之后配置,providers数组配置正确:
// app.module.ts import { NgModule } from '@angular/core'; import { BrowserModule } from '@angular/platform-browser'; import { HttpClientModule, HTTP_INTERCEPTORS } from '@angular/common/http'; import { AppComponent } from './app.component'; import { AuthInterceptor } from './auth.interceptor'; @NgModule({ declarations: [AppComponent], imports: [BrowserModule, HttpClientModule], // 先导入HttpClientModule providers: [ { provide: HTTP_INTERCEPTORS, useClass: AuthInterceptor, multi: true } ], bootstrap: [AppComponent] }) export class AppModule { }
额外排查点
- 检查是否有其他代码(如路由守卫)在登录流程中提前发起HTTP请求,导致拦截器先执行
- 在拦截器和AuthService的setToken方法中添加日志,确认执行顺序:
通过控制台输出确认拦截器是否在// auth.service.ts setToken setToken(token: string): void { console.log('Token已存入localStorage:', token); localStorage.setItem('token', token); } // auth.interceptor.ts intercept intercept(request: HttpRequest<unknown>, next: HttpHandler): Observable<HttpEvent<unknown>> { const token = localStorage.getItem('token'); console.log('拦截器读取token:', token); // 后续逻辑 }Token已存入localStorage日志前就打印了读取token的内容
内容的提问来源于stack exchange,提问作者Omar Khaled
相关产品推荐
相关产品推荐

