# 错误响应对比:优化前 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 格式,或者不传此字段"
}
]
}
}
}
}
}
}
)
```