# 错误响应对比:优化前 vs 优化后 ## 场景 1: UUID 格式错误 ### ❌ 优化前(暴露技术细节) ```json { "success": false, "code": 422, "message": "body -> folderId: Input should be a valid UUID, invalid character: expected an optional prefix of `urn:uuid:` followed by [0-9a-fA-F-], found `v` at 1", "data": { "errors": [ { "type": "uuid_parsing", // ⚠️ 暴露 Pydantic 内部类型 "loc": ["body", "folderId"], "msg": "Input should be a valid UUID, invalid character: expected an optional prefix of `urn:uuid:` followed by [0-9a-fA-F-], found `v` at 1", "input": "virtual-mine", "ctx": { // ⚠️ 暴露验证上下文 "error": "invalid character: expected an optional prefix of `urn:uuid:` followed by [0-9a-fA-F-], found `v` at 1" }, "url": "https://errors.pydantic.dev/2.12/v/uuid_parsing" // ⚠️ 暴露框架版本 } ] }, "timestamp": "2026-02-05T08:00:04.953349+00:00" } ``` **问题点**: - 🔴 暴露使用 Pydantic 2.12 - 🔴 技术术语 `uuid_parsing` 对用户无意义 - 🔴 错误消息过于技术化 - 🔴 提供了 Pydantic 文档链接(不必要) --- ### ✅ 优化后(用户友好) ```json { "success": false, "code": 422, "message": "folderId: 必须是有效的 UUID 格式,或者不传此字段", "data": { "errors": [ { "field": "folderId", "message": "必须是有效的 UUID 格式,或者不传此字段" } ] }, "timestamp": "2026-02-05T08:00:04.953349+00:00" } ``` **改进点**: - ✅ 隐藏了技术实现细节 - ✅ 清晰的字段名 - ✅ 易懂的错误说明 - ✅ 提供了解决建议 --- ## 场景 2: 数值范围错误 ### ❌ 优化前 ```json { "success": false, "code": 422, "message": "body -> plannedDuration: Input should be greater than 0", "data": { "errors": [ { "type": "greater_than", // ⚠️ 技术术语 "loc": ["body", "plannedDuration"], "msg": "Input should be greater than 0", "input": 0, "ctx": { // ⚠️ 暴露验证规则 "gt": 0 }, "url": "https://errors.pydantic.dev/2.12/v/greater_than" } ] }, "timestamp": "2026-02-05T08:00:04.953349+00:00" } ``` --- ### ✅ 优化后 ```json { "success": false, "code": 422, "message": "plannedDuration: 必须大于 0,或者不传此字段", "data": { "errors": [ { "field": "plannedDuration", "message": "必须大于 0,或者不传此字段" } ] }, "timestamp": "2026-02-05T08:00:04.953349+00:00" } ``` --- ## 场景 3: 多个字段错误 ### ❌ 优化前 ```json { "success": false, "code": 422, "message": "body -> folderId: Input should be a valid UUID...", "data": { "errors": [ { "type": "uuid_parsing", "loc": ["body", "folderId"], "msg": "Input should be a valid UUID, invalid character...", "input": "virtual-mine", "ctx": { "error": "..." }, "url": "https://errors.pydantic.dev/2.12/v/uuid_parsing" }, { "type": "greater_than", "loc": ["body", "plannedDuration"], "msg": "Input should be greater than 0", "input": 0, "ctx": { "gt": 0 }, "url": "https://errors.pydantic.dev/2.12/v/greater_than" } ] }, "timestamp": "2026-02-05T08:00:04.953349+00:00" } ``` **问题**: - 每个错误都包含大量技术细节 - 用户需要自己理解并转换这些信息 - 增加了响应体积 --- ### ✅ 优化后 ```json { "success": false, "code": 422, "message": "参数验证失败,共 2 个错误", "data": { "errors": [ { "field": "folderId", "message": "必须是有效的 UUID 格式,或者不传此字段" }, { "field": "plannedDuration", "message": "必须大于 0,或者不传此字段" } ] }, "timestamp": "2026-02-05T08:00:04.953349+00:00" } ``` **改进**: - 简洁的错误列表 - 统一的消息格式 - 减少了响应体积 - 更容易在前端展示 --- ## 场景 4: 字符串长度错误 ### ✅ 优化后示例 #### 长度过短 ```json { "success": false, "code": 422, "message": "name: 长度不能少于 1 个字符", "data": { "errors": [ { "field": "name", "message": "长度不能少于 1 个字符" } ] } } ``` #### 长度过长 ```json { "success": false, "code": 422, "message": "name: 长度不能超过 255 个字符", "data": { "errors": [ { "field": "name", "message": "长度不能超过 255 个字符" } ] } } ``` --- ## 场景 5: 必填字段缺失 ### ✅ 优化后 ```json { "success": false, "code": 422, "message": "name: 此字段为必填项", "data": { "errors": [ { "field": "name", "message": "此字段为必填项" } ] } } ``` --- ## 前端集成示例 ### Vue 3 + Element Plus ```vue ``` --- ## 对比总结 | 维度 | 优化前 | 优化后 | |------|--------|--------| | **安全性** | ⚠️ 暴露技术栈和版本 | ✅ 隐藏实现细节 | | **用户体验** | ⚠️ 技术术语难懂 | ✅ 清晰易懂的提示 | | **响应大小** | ⚠️ 包含大量冗余信息 | ✅ 精简高效 | | **前端集成** | ⚠️ 需要额外处理 | ✅ 直接使用 | | **调试能力** | ✅ 详细信息 | ✅ 日志中保留详情 | | **可维护性** | ⚠️ 依赖框架输出 | ✅ 统一可控 | --- ## 额外建议 ### 1. 生产环境配置 ```bash # .env.production DEBUG=false ENVIRONMENT=production ``` ### 2. 错误监控 ```python # 在异常处理器中添加错误监控 import sentry_sdk if settings.ENVIRONMENT == "production": logger.error(f"验证错误: {exc.errors()}") sentry_sdk.capture_exception(exc) ``` ### 3. API 文档 在 Swagger/OpenAPI 文档中说明错误响应格式: ```python @router.post( "", responses={ 422: { "description": "参数验证失败", "content": { "application/json": { "example": { "success": False, "code": 422, "message": "folderId: 必须是有效的 UUID 格式", "data": { "errors": [ { "field": "folderId", "message": "必须是有效的 UUID 格式,或者不传此字段" } ] } } } } } } ) ```