Angular 19使用provideAppInitializer获取CSRF Token Cookie故障排查
问题排查与修复方案
核心错误1:Promise未正确触发状态变更
你的fetch_token方法创建了Promise,但在HTTP请求完成后没有调用resolve或reject,导致这个Promise永远处于pending状态。Angular的provideAppInitializer需要依赖返回的Promise来判断初始化是否完成,现在的代码等于没让应用等待Token请求结束。
修复CsrfService的fetch_token方法:
fetch_token(): Promise<void> { return new Promise((resolve, reject) => { // 注意补充完整请求协议与端口,比如http://localhost:8000/xxx this.http.get<{ token: string }>('http://localhost:8000/api/get-csrf-token', { withCredentials: true }) .subscribe({ next: (response) => { this.token = response.token; resolve(); // 请求成功后标记Promise完成 }, error: (error) => { console.error('Error fetching CSRF token', error); reject(error); // 请求失败时标记Promise异常 }, }); }); }
核心错误2:初始化器未返回Promise
在provideAppInitializer的回调里,你调用了fetch_token但没有返回这个Promise,Angular无法追踪异步操作的完成状态,自然不会等待Token请求完成就启动应用。
修复app.config.ts的初始化器配置:
provideAppInitializer(() => { return inject(CsrfService).fetch_token(); // 返回Promise,让Angular等待初始化完成 })
额外优化:贴合Django CSRF规范的简化方案
其实你不需要手动存储Token,Django的CSRF机制只需要两点就能自动处理:
- 所有请求携带
withCredentials: true,让浏览器自动保存并发送CSRF Cookie - 配置Angular HTTP拦截器,自动从Cookie中读取
csrftoken并添加到请求头X-CSRFToken
示例拦截器代码:
import { HttpInterceptorFn } from '@angular/common/http'; export const csrfInterceptor: HttpInterceptorFn = (req, next) => { // 仅对非安全请求(非GET/HEAD/OPTIONS)添加CSRF头 if (!req.method.match(/GET|HEAD|OPTIONS/)) { const csrfToken = document.cookie.split('; ') .find(row => row.startsWith('csrftoken=')) ?.split('=')[1]; if (csrfToken) { req = req.clone({ headers: req.headers.set('X-CSRFToken', csrfToken) }); } } return next(req); };
然后在app.config.ts中注册拦截器:
provideHttpClient(withInterceptors([csrfInterceptor])),
只要你的Django后端通过CsrfViewMiddleware中间件(或自定义接口)正确设置了CSRF Cookie,浏览器会自动处理Cookie的存储与携带,甚至不需要手动调用初始化接口。
其他注意事项
- 请求URL必须完整:
localhost/fake/url要补充协议(如http://)和对应端口(如8000),否则浏览器会解析错误 - 确保前后端同域:域名、端口、协议必须完全一致,否则Cookie无法正常跨域携带
内容的提问来源于stack exchange,提问作者user25752829
相关产品推荐
相关产品推荐

