AspNetBoilerplate的Angular4项目中Chrome DevTools重复请求原因
先看你提供的NSwag生成的请求代码:
userApplyLimitAsync(): Observable<GetUserApplyLimitOutput> { let url_ = this.baseUrl + "/api/services/app/AElfApplication/UserApplyLimitAsync"; url_ = url_.replace(/[?&]$/, ""); let options_ = { method: "post", headers: new Headers({ "Content-Type": "application/json", "Accept": "application/json" }) }; return this.http.request(url_, options_).flatMap((response_) => { return this.processUserApplyLimitAsync(response_); }).catch((response_: any) => { if (response_ instanceof Response) { try { return this.processUserApplyLimitAsync(response_); } catch (e) { return <Observable<GetUserApplyLimitOutput>><any>Observable.throw(e); } } else return <Observable<GetUserApplyLimitOutput>><any>Observable.throw(response_); }); } protected processUserApplyLimitAsync(response: Response): Observable<GetUserApplyLimitOutput> { const status = response.status; let _headers: any = response.headers ? response.headers.toJSON() : {}; if (status === 200) { const _responseText = response.text(); let result200: any = null; let resultData200 = _responseText === "" ? null : JSON.parse(_responseText, this.jsonParseReviver); result200 = resultData200 ? GetUserApplyLimitOutput.fromJS(resultData200) : new GetUserApplyLimitOutput(); return Observable.of(result200); } else if (status !== 200 && status !== 204) { const _responseText = response.text(); return throwException("An unexpected server error occurred.", status, _responseText, _headers); } return Observable.of<GetUserApplyLimitOutput>(<any>null); }
以及调用代码:
this._withdrawService.userApplyLimitAsync() .subscribe((result) => { this.withdrawActive = result.isSucceed; });
结合你的开发场景,我整理了几个最可能导致两次相同POST请求的原因,按排查优先级排序:
1. 组件/服务中重复调用了userApplyLimitAsync()
这是最常见的触发原因。比如你的组件ngOnInit钩子被触发了两次(路由配置重复、组件在模板中被重复渲染),或者这段订阅代码被放在了会重复执行的逻辑里(比如ngOnChanges中且触发频繁)。
排查方法:在userApplyLimitAsync()方法第一行加个日志:
console.log('userApplyLimitAsync 被调用了');
如果控制台打印两次,说明方法被调用了两次,去追踪调用它的代码为什么执行多次。
2. Observable被重复订阅
Angular的HTTP请求返回的是冷Observable——每一次订阅都会发起一次全新的请求。即使你只写了一次.subscribe(),如果这个Observable被其他地方(比如模板里的async管道、另一段业务代码)额外订阅了,就会触发两次请求。
排查方法:
- 检查组件模板有没有用
async管道绑定这个方法返回的Observable(比如*ngIf="(_withdrawService.userApplyLimitAsync() | async) as result") - 在
return this.http.request(url_, options_)前加日志:
如果打印两次但console.log('发起HTTP请求');userApplyLimitAsync只打印一次,说明Observable被重复订阅了。
3. AspNetBoilerplate的Token自动刷新机制导致
AspNetBoilerplate的Angular客户端内置了AbpHttpInterceptor,当请求携带的AccessToken过期时,拦截器会自动刷新Token,然后重新发起原请求。这就会出现两次请求:第一次是带过期Token的请求(通常返回401),第二次是带新Token的正常请求(返回200)。
排查方法:查看Network面板中两次请求的响应状态码,如果第一次是401,第二次是200,那就是这个原因——这是ABP框架的正常行为,用于自动处理Token过期,不需要额外修改。
4. NSwag生成代码的异常处理逻辑(可能性低)
看你提供的代码,catch块里会对Response类型的错误再次调用processUserApplyLimitAsync,但这个逻辑是处理响应内容,不会发起新请求。除非第一次请求返回非200/204状态码,这个逻辑会解析响应并抛出异常,但只会是一次请求的两次处理,不会出现两次POST请求,所以这个可能性很低。
快速排查步骤总结
- 先确认
userApplyLimitAsync()是否被调用两次; - 再确认HTTP请求是否被发起两次(排除重复订阅);
- 最后检查请求的响应状态码,判断是否是Token刷新导致。
内容的提问来源于stack exchange,提问作者zhengkai wang

