Angular中RxJS订阅的error方法完全不执行问题排查
问题描述
我有一个向Node.js后端发起HTTP请求的Angular组件,未使用NgRx,通过服务处理请求。遇到的问题是:收到后端错误响应时,订阅中的error方法完全不执行,仅能在开发者工具看到状态码和消息,但next回调运行正常。
相关代码
组件代码
this.httpCF .getPercentagesByName(this.name) .subscribe({ next: (response) => { console.log('response get by name'); console.log(response); // 正常工作 }, error: (error) => { console.log('error'); // 错误响应时完全不执行... }, });
服务代码
getPercentagesByName(name: string) { return this.http.post( environment.ApiGetByName, { name: name }, { headers: this.headers } ); }
Node.js后端响应代码
尝试过两种写法:
res.status(404).send({ msg: 'Element not found' })
res.status(404).json({ msg: 'Element not found' })
补充:HttpInterceptor代码
export class TokenInterceptor implements HttpInterceptor { constructor( private auth: AngularFireAuth, private router: Router, private _snackBar: MatSnackBar ) {} intercept( request: HttpRequest<any>, next: HttpHandler ): Observable<HttpEvent<any>> { return next.handle(request).pipe( catchError((error: HttpEvent<any>) => { if (error instanceof HttpErrorResponse) { if (!(error.error instanceof ErrorEvent)) { if (error.status === 401) { // token过期时,登出并跳转到登录页 this.auth.signOut().then(() => { if (this.router.url !== '/auth/login') { this._snackBar.open( 'Session expired, please login...', 'Close', { duration: 5000, panelClass: 'expiredtoken', } ); this.router.navigate(['/auth/login']); } }); } } } return of(error); }) ); } }
问题原因与解决方法
问题出在HttpInterceptor的catchError处理逻辑上:
拦截器捕获到错误后,使用return of(error)将错误包装成了一个正常的Observable流,导致订阅者的next回调接收到错误对象,而非触发error回调。
修正后的拦截器代码
import { throwError } from 'rxjs'; // 需导入throwError操作符 export class TokenInterceptor implements HttpInterceptor { constructor( private auth: AngularFireAuth, private router: Router, private _snackBar: MatSnackBar ) {} intercept( request: HttpRequest<any>, next: HttpHandler ): Observable<HttpEvent<any>> { return next.handle(request).pipe( catchError((error: HttpErrorResponse) => { if (error instanceof HttpErrorResponse) { if (!(error.error instanceof ErrorEvent)) { if (error.status === 401) { // token过期时,执行登出与跳转逻辑 this.auth.signOut().then(() => { if (this.router.url !== '/auth/login') { this._snackBar.open( '会话已过期,请重新登录...', '关闭', { duration: 5000, panelClass: 'expiredtoken', } ); this.router.navigate(['/auth/login']); } }); } } } // 重新抛出错误,触发订阅者的error回调 return throwError(() => error); }) ); } }
关键说明
of(error)会创建一个发射错误对象的正常Observable,订阅者的next回调会接收该对象,不会触发error回调。throwError(() => error)会创建一个发射错误的Observable,确保订阅者的error回调被正确触发。- 必须从
rxjs包中导入throwError操作符才能使用。
内容的提问来源于stack exchange,提问作者Federico Rojas
相关产品推荐
相关产品推荐

