You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
4.7 KiB
4.7 KiB
错误处理优化说明
📋 优化目标
- 提升安全性:不暴露内部技术实现细节
- 改善用户体验:提供清晰、友好的错误提示
- 保持可调试性:开发环境下保留详细日志
⚠️ 优化前的问题
暴露的敏感信息
{
"success": false,
"code": 422,
"message": "body -> folderId: Input should be a valid UUID...",
"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:`..."
},
"url": "https://errors.pydantic.dev/2.12/v/uuid_parsing" // ❌ 暴露框架版本
}
]
}
}
存在的安全隐患
- ✖️ 暴露后端使用 Pydantic 2.12
- ✖️ 暴露内部验证逻辑和规则
- ✖️ 技术术语对普通用户不友好
- ✖️ 提供了探测系统的信息
✅ 优化后的响应
友好的错误格式
{
"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"
}
优势
- ✅ 隐藏了技术实现细节
- ✅ 提供清晰的字段名和错误说明
- ✅ 给出了解决建议("或者不传此字段")
- ✅ 只返回必要的业务信息
- ✅ 更符合 RESTful API 最佳实践
🔒 错误类型映射表
| Pydantic 错误类型 | 用户友好消息 |
|---|---|
uuid_parsing |
必须是有效的 UUID 格式,或者不传此字段 |
greater_than |
必须大于 {值},或者不传此字段 |
string_too_short |
长度不能少于 {min} 个字符 |
string_too_long |
长度不能超过 {max} 个字符 |
missing |
此字段为必填项 |
string_pattern_mismatch |
格式不正确 |
value_error |
值不合法 |
🛠️ 开发调试
在开发环境中(DEBUG=True),详细的验证错误会记录在日志中:
WARNING - 验证错误详情: [{'type': 'uuid_parsing', 'loc': ('body', 'folderId'), ...}]
这样既保证了生产环境的安全性,又方便开发人员调试。
📝 使用建议
前端错误处理
try {
const response = await createProject(data);
} catch (error) {
if (error.code === 422 && error.data?.errors) {
// 显示友好的错误提示
error.data.errors.forEach(err => {
showFieldError(err.field, err.message);
});
} else {
showGeneralError(error.message);
}
}
字段级错误提示示例
📍 folderId: 必须是有效的 UUID 格式,或者不传此字段
📍 plannedDuration: 必须大于 0,或者不传此字段
🔐 安全最佳实践
-
永远不要返回:
- 内部错误堆栈信息
- 数据库错误详情
- 框架版本和类型
- 文件路径和系统信息
-
应该返回:
- 用户可操作的错误信息
- 字段名称和位置
- 验证规则的简要说明
- 修复建议
-
分环境处理:
- 生产环境:简洁、安全的错误消息
- 开发环境:详细的调试信息(仅在日志中)
- 测试环境:保留适度的详细信息
📊 错误响应示例对比
单字段错误
// 优化后
{
"success": false,
"code": 422,
"message": "folderId: 必须是有效的 UUID 格式,或者不传此字段",
"data": {
"errors": [
{
"field": "folderId",
"message": "必须是有效的 UUID 格式,或者不传此字段"
}
]
},
"timestamp": "2026-02-05T08:00:04.953349+00:00"
}
多字段错误
// 优化后
{
"success": false,
"code": 422,
"message": "参数验证失败,共 3 个错误",
"data": {
"errors": [
{
"field": "name",
"message": "此字段为必填项"
},
{
"field": "folderId",
"message": "必须是有效的 UUID 格式,或者不传此字段"
},
{
"field": "plannedDuration",
"message": "必须大于 0,或者不传此字段"
}
]
},
"timestamp": "2026-02-05T08:00:04.953349+00:00"
}
🎯 总结
通过这次优化:
- ✅ 提升了 API 的安全性
- ✅ 改善了用户体验
- ✅ 保持了开发调试的便利性
- ✅ 符合生产环境的最佳实践