Angular错误处理实现:区分错误场景实现通知展示或页面跳转
方案合理性判断
你提出的自定义错误类层级的方案完全合理,核心优势如下:
- 完全和后端实现解耦,无需修改后端响应结构,不会影响其他调用方使用API
- 错误处理逻辑收敛在业务侧,全局错误处理器只需要根据错误类的类型执行对应的通用逻辑,不需要感知业务场景差异
- 后续新增业务场景只需要扩展新的错误子类即可,符合开闭原则
更优的落地思路(适配你当前NgRx技术栈,无需大改现有逻辑)
步骤1:统一封装错误转换逻辑,避免重复代码
先定义业务错误类层级,再封装公共工具把HttpErrorResponse转换为对应的自定义错误实例,逻辑放在公共工具层,不需要每个业务模块重复开发:
// 基础业务错误类 export class BusinessError extends Error { constructor(public statusCode: number, public message: string) { super(message); this.name = 'BusinessError'; } } // 无权限错误类 export class NoPermissionError extends BusinessError { constructor(message: string) { super(403, message); this.name = 'NoPermissionError'; } } // 资源不存在错误类 export class ResourceNotFoundError extends BusinessError { constructor(message: string, public scene?: string) { super(404, message); this.name = 'ResourceNotFoundError'; } } // 公共错误转换工具 export function convertHttpError(error: HttpErrorResponse): BusinessError { switch(error.status) { case 403: return new NoPermissionError(error.error?.message || '您无权限访问该资源'); case 404: return new ResourceNotFoundError(error.error?.message || '请求的资源不存在'); default: return new BusinessError(error.status, error.error?.message || '操作失败,请稍后重试'); } }
修改orderService直接复用转换逻辑,不需要改上层调用代码:
public getOrders(): Observable < Order[] > { return this.http.get < Order[] > (this.api.getUrl('api/orders'), this.api.getHeaders()) .pipe( catchError((err: HttpErrorResponse) => throwError(() => convertHttpError(err))) ) }
步骤2:拆分通用错误和业务专属错误的处理逻辑
- 通用逻辑(比如403全局跳转首页)放在全局错误处理器中统一处理,不需要每个业务场景重复实现:
@Injectable() export class GlobalErrorHandler implements ErrorHandler { constructor(private router: Router, private toast: ToastService) {} handleError(error: unknown): void { if (error instanceof NoPermissionError) { this.toast.error(error.message); this.router.navigate(['/home']); return; } // 其他通用逻辑:500错误上报日志、网络异常提示等 } }
- 业务专属逻辑(比如订单列表的404要显示「当前暂无订单」提示)放在对应业务的Effect中监听失败Action处理即可,修改你原有的失败Action定义,把传递
errorMessage改为传递完整错误实例:
// Effect中的catchError修改 catchError((error: BusinessError) => of(SurveyActions.getOrdersFailure({ error }))) // 新增订单请求失败处理Effect handleOrderFail$ = createEffect( () => this.actions$.pipe( ofType(OrderActions.getOrdersFailure), map(({ error }) => { if (error instanceof ResourceNotFoundError) { this.toast.info('当前暂无订单'); } else { this.toast.error(error.message); } }) ), { dispatch: false } )
可选优化:错误逻辑多态实现
如果后续业务场景增多,不想写大量if判断,可以给错误类新增handle方法,不同错误类型自己实现处理逻辑,调用方直接执行即可:
export class ResourceNotFoundError extends BusinessError { constructor(message: string, public scene?: string) { super(404, message); this.name = 'ResourceNotFoundError'; } handle(toast: ToastService) { if (this.scene === 'orderList') { toast.info('当前暂无订单'); } else { toast.error(this.message); } } } // 调用方不需要判断类型,直接执行 error.handle(this.toast);
内容的提问来源于stack exchange,提问作者matikowy
相关产品推荐
相关产品推荐

