Angular 6.1.10中APP_INITIALIZER加载后端信息时出现未知HTTP错误
问题分析与解决方案
这个问题我之前在旧版Firefox环境下也碰到过类似情况,咱们来拆解下原因和对应的解决办法:
错误根源
在Firefox 60.4.0 ESR及更早的版本里,当你快速连续刷新页面时,浏览器会立刻中止上一次页面加载过程中还没完成的AJAX请求——这是浏览器为了清理资源的默认行为。而Angular的HttpClient会把这种请求被中止的情况,转化为你看到的Http failure response for (unknown url): 0 Unknown Error。
对应到你的场景就是:
- 第一次刷新触发
APP_INITIALIZER,loadSecurityInfo发起请求; - 请求还没拿到响应,你又点了第二次刷新,浏览器直接终止了前一个请求;
- 你的
catchError逻辑没有区分“请求被用户刷新中止”和真正的后端服务错误,所以控制台就抛出了这个0状态码的错误。
新版Firefox和Chrome对这种场景做了优化,要么不会中止这类初始化请求,要么对请求中止的错误处理更温和,所以不会出现这个问题。
解决办法
你只需要在错误处理逻辑里识别出“请求被中止”的情况,忽略这类错误或者返回一个默认的安全信息对象,就能避免干扰应用初始化流程。
方案1:修改loadSecurityInfo的错误处理
直接在catchError里添加判断逻辑:
import { of } from 'rxjs'; // 记得导入of操作符 loadSecurityInfo(reconstituteSecurity = false): Observable<SecurityInfo> { console.log(`Loading SecurityInfo - Reconstitute security? ${reconstituteSecurity}`); return this.http .get<any>(this.securityInfoUrl, {headers: this.headers}) .pipe( map(body => { this._securityInfo = new SecurityInfo(); this._securityInfo.isAuthenticationEnabled = body.authenticationEnabled; this._securityInfo.isAuthenticated = body.authenticated; this._securityInfo.username = body.username; this._securityInfo.roles = body.roles as string[]; console.log(`Getting security info: ${JSON.stringify(this.securityInfo)}`); return this._securityInfo; }), catchError(error => { // 判断是否是请求被中止的错误(旧Firefox快速刷新场景) if (error.status === 0 || error.name === 'AbortError') { console.warn('Security info request was aborted due to page refresh'); // 返回一个默认的SecurityInfo实例,保证后续逻辑能正常运行 return of(new SecurityInfo()); } // 其他真实错误交给原错误处理逻辑 return this.errorReporter.handleError('loadSecurityInfo', null)(error); }) ); }
方案2:在APP_INITIALIZER的初始化函数中处理
也可以在将Observable转为Promise的环节处理错误:
export function init(authService: AuthService) { return () => { return authService.loadSecurityInfo(true).toPromise() .catch(err => { // 忽略刷新导致的中止错误 if (err.status === 0 || err.name === 'AbortError') { console.warn('Initial security info load aborted by page refresh'); // 返回默认对象,确保Promise不拒绝,应用能正常初始化 return new SecurityInfo(); } // 其他错误继续抛出,让错误处理机制捕获 throw err; }); }; }
注意:返回的默认SecurityInfo要保证属性符合你的应用逻辑,比如可以给isAuthenticationEnabled设为false,避免后续权限判断出现异常。
内容的提问来源于stack exchange,提问作者All_Safe
相关产品推荐
相关产品推荐

