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.
5.3 KiB
5.3 KiB
统一错误响应格式实现
日期: 2026-01-27
类型: 功能增强
影响范围: 全局 API 错误处理
变更概述
实现全局异常处理器,确保所有 API 错误响应符合统一的 ApiResponse 格式规范。
问题背景
在实现统一响应格式(RFC-135)后,发现错误响应仍使用 FastAPI 默认格式:
{
"detail": "错误信息"
}
这与成功响应的 ApiResponse 格式不一致,导致前端需要处理两种不同的响应结构。
解决方案
1. 添加全局异常处理器
在 app/main.py 中添加三个异常处理器:
HTTPException 处理器
@app.exception_handler(HTTPException)
async def http_exception_handler(request: Request, exc: HTTPException):
return JSONResponse(
status_code=exc.status_code,
content={
"success": False,
"code": exc.status_code,
"message": exc.detail,
"data": None,
"timestamp": datetime.now(timezone.utc).isoformat()
}
)
RequestValidationError 处理器
@app.exception_handler(RequestValidationError)
async def validation_exception_handler(request: Request, exc: RequestValidationError):
error_msg = "请求参数验证失败"
if exc.errors():
first_error = exc.errors()[0]
field = " -> ".join(str(loc) for loc in first_error.get("loc", []))
msg = first_error.get("msg", "")
error_msg = f"{field}: {msg}"
return JSONResponse(
status_code=422,
content={
"success": False,
"code": 422,
"message": error_msg,
"data": {"errors": exc.errors()},
"timestamp": datetime.now(timezone.utc).isoformat()
}
)
通用异常处理器
@app.exception_handler(Exception)
async def general_exception_handler(request: Request, exc: Exception):
logger.error(f"未处理的异常: {exc}", exc_info=True)
return JSONResponse(
status_code=500,
content={
"success": False,
"code": 500,
"message": "服务器内部错误" if not settings.DEBUG else str(exc),
"data": None,
"timestamp": datetime.now(timezone.utc).isoformat()
}
)
404 错误处理器
@app.exception_handler(404)
async def not_found_handler(request: Request, exc):
return JSONResponse(
status_code=404,
content={
"success": False,
"code": 404,
"message": "请求的资源不存在",
"data": None,
"timestamp": datetime.now(timezone.utc).isoformat()
}
)
测试验证
1. 业务逻辑错误(400)
curl -X POST "http://localhost:6170/api/v1/auth/login/phone" \
-H "Content-Type: application/json" \
-d '{"phone":"18046315592","countryCode":"+86","code":"000000"}'
响应:
{
"success": false,
"code": 400,
"message": "验证码错误",
"data": null,
"timestamp": "2026-01-27T08:23:00.310624+00:00"
}
2. 参数验证错误(422)
curl -X POST "http://localhost:6170/api/v1/auth/login/phone" \
-H "Content-Type: application/json" \
-d '{"phone":"18046315592"}'
响应:
{
"success": false,
"code": 422,
"message": "body -> code: Field required",
"data": {
"errors": [...]
},
"timestamp": "2026-01-27T08:23:12.388333+00:00"
}
3. 资源不存在(404)
curl -X GET "http://localhost:6170/api/v1/nonexistent"
响应:
{
"success": false,
"code": 404,
"message": "请求的资源不存在",
"data": null,
"timestamp": "2026-01-27T08:24:07.692476+00:00"
}
4. 限流错误(429)
curl -X POST "http://localhost:6170/api/v1/auth/sms/send" \
-H "Content-Type: application/json" \
-d '{"phone":"15980906230","countryCode":"+86","purpose":"login"}'
响应:
{
"success": false,
"code": 429,
"message": "今日发送次数已达上限",
"data": null,
"timestamp": "2026-01-27T08:21:32.130535+00:00"
}
影响范围
受影响的异常类型
ValidationError(400)AuthenticationError(401)PermissionError(403)NotFoundError(404)InsufficientCreditsError(402)RateLimitError(429)RequestValidationError(422)- 所有未捕获的异常 (500)
前端适配
前端现在可以统一处理所有 API 响应:
interface ApiResponse<T> {
success: boolean;
code: number;
message: string;
data: T | null;
timestamp: string;
}
// 统一错误处理
if (!response.success) {
showError(response.message);
}
技术细节
异常处理优先级
- 特定状态码处理器(如 404)
- HTTPException 处理器
- RequestValidationError 处理器
- 通用 Exception 处理器
日志记录
- 500 错误会记录完整堆栈信息
- DEBUG 模式下返回详细错误信息
- 生产环境返回通用错误提示
相关文档
部署说明
无需数据库迁移,重启应用即可生效。
后续优化
- 添加错误码枚举,细化错误类型
- 支持国际化错误消息
- 添加错误追踪 ID(trace_id)