# 异常处理规范 > 最后更新:2025-12-25 > 本文档定义前后端统一的异常处理策略 --- ## 一、设计原则 ### 1.1 核心目标 1. **用户友好**:错误信息对用户清晰易懂 2. **调试便捷**:保留足够的日志信息用于排查问题 3. **一致性**:前后端采用统一的错误响应格式 ### 1.2 HTTP 状态码策略 | 场景 | HTTP状态码 | 业务码 | 说明 | |------|-----------|--------|------| | 登录失败(密码错误) | 200 | 400 | 便于前端友好提示 | | Token无效/过期 | 401 | - | 触发前端自动登出 | | 权限不足 | 403 | - | 标准HTTP语义 | | 资源不存在 | 404 | - | 标准HTTP语义 | | 服务器错误 | 500 | - | 标准HTTP语义 | --- ## 二、后端异常处理 ### 2.1 统一响应格式 ```python # app/schemas/base.py class ResponseModel(BaseModel): code: int = 200 # 业务状态码 message: str = "success" # 业务消息 data: Any = None # 响应数据 ``` ### 2.2 登录异常处理 **设计决策**:登录失败返回 HTTP 200 + 业务错误码 ```python # 正确做法 @router.post("/login") async def login(login_data: LoginRequest): try: user, token = await auth_service.login(...) return ResponseModel(data={...}) except UnauthorizedError as e: # 记录日志 logger.warning("login_failed", username=login_data.username) # 返回 HTTP 200 + 业务失败码 return ResponseModel( code=400, message="用户名或密码错误", data=None, ) ``` **原因说明**: - 避免浏览器弹出 HTTP 401 认证对话框 - 前端可以统一处理业务错误,展示友好提示 - 区分"未登录"(401)和"登录失败"(200+400)的语义 ### 2.3 全局异常处理 ```python # app/main.py @app.exception_handler(Exception) async def global_exception_handler(request, exc): logger.error(f"未处理的异常: {exc}", exc_info=True) return JSONResponse( status_code=500, content={ "code": 500, "message": "内部服务器错误", "detail": str(exc) if settings.DEBUG else None, }, ) ``` --- ## 三、前端异常处理 ### 3.1 HTTP 错误拦截 ```typescript // src/api/request.ts } catch (error) { const errorInfo = handleHttpError(error) // 401 统一处理:清理认证状态并重定向 try { const status = (errorInfo as any)?.status || (error as any)?.status if (status === 401) { console.warn('[Auth] Token过期或无效,正在清理认证状态', { url, status }) localStorage.removeItem('access_token') localStorage.removeItem('refresh_token') localStorage.removeItem('current_user') if (!location.pathname.startsWith('/login')) { console.info('[Auth] 重定向到登录页') location.href = '/login' } } } catch (authError) { // 认证处理过程中的异常需要记录,但不影响主流程 console.error('[Auth] 处理401错误时发生异常:', authError) } throw errorInfo } ``` ### 3.2 日志规范 | 级别 | 使用场景 | 示例 | |------|---------|------| | `console.error` | 程序错误、异常 | 网络错误、解析失败 | | `console.warn` | 预期内的失败 | Token过期、密码错误 | | `console.info` | 关键操作记录 | 登录成功、页面跳转 | | `console.log` | 开发调试(生产禁用) | 变量打印 | ### 3.3 错误信息展示 ```typescript // 业务错误(code !== 200) if (response.code !== 200) { ElMessage.error(response.message || '操作失败') } // HTTP 错误 catch (error) { ElMessage.error(error.message || '网络请求失败') } ``` --- ## 四、最佳实践 ### 4.1 DO(推荐) - ✅ 使用统一的 ResponseModel 格式 - ✅ 异常处理中添加日志记录 - ✅ 区分用户提示信息和调试信息 - ✅ 401 错误自动清理认证状态 ### 4.2 DON'T(避免) - ❌ 静默吞掉异常 `catch (_) {}` - ❌ 在用户提示中暴露技术细节 - ❌ 忘记处理边界情况(网络超时等) - ❌ 生产环境使用 console.log --- ## 五、错误码对照表 | 业务码 | 含义 | 前端处理 | |--------|------|---------| | 200 | 成功 | 正常流程 | | 400 | 业务失败(如密码错误) | 显示 message | | 401 | 未认证 | 跳转登录页 | | 403 | 无权限 | 显示无权限提示 | | 404 | 资源不存在 | 显示不存在提示 | | 500 | 服务器错误 | 显示通用错误 | --- ## 六、变更记录 | 日期 | 内容 | 作者 | |------|------|------| | 2025-12-25 | 初始版本,明确登录异常处理策略 | AI Assistant |