本文目录导读:

- 核心思想
- 方案一:使用 Flask 的
jsonify封装函数 - 方案二:使用 Flask 的
after_request钩子 - 方案三:使用 FastAPI 和 Pydantic 模型
- 方案四:使用第三方库
- 关键设计原则
- 示例:完整的企业级响应格式
在Python Web开发中(尤其是使用Flask、FastAPI等框架时),统一返回数据格式是一个非常常见的需求,它能确保前端调用API时,无论成功或失败,都能按照固定的结构解析数据。
下面我会介绍几种主流方案,以Flask和FastAPI为例。
核心思想
定义一个标准的响应体结构,通常包含:
{
"code": 200, // 状态码 (业务状态码,非HTTP状态码)
"message": "success", // 提示信息
"data": {} // 实际数据 (可以是字典、列表或null)
}
使用 Flask 的 jsonify 封装函数
这是最直接、最灵活的方式。
from flask import Flask, jsonify
app = Flask(__name__)
def success(data=None, message="success", code=200):
"""成功响应"""
return jsonify({
"code": code,
"message": message,
"data": data
})
def error(message="error", code=400, data=None):
"""失败响应"""
return jsonify({
"code": code,
"message": message,
"data": data
})
@app.route('/user/<int:user_id>')
def get_user(user_id):
if user_id == 1:
return success(data={"name": "Alice", "age": 30})
else:
return error(message="User not found", code=404)
# 更高级:使用装饰器自动包装
from functools import wraps
def standard_response(func):
@wraps(func)
def wrapper(*args, **kwargs):
try:
result = func(*args, **kwargs)
# 如果视图函数已经返回了Response对象,直接返回
if isinstance(result, tuple):
return result
return success(data=result)
except Exception as e:
return error(message=str(e), code=500)
return wrapper
@app.route('/list')
@standard_response
def get_list():
# 函数只需要返回数据,装饰器会自动包装
return ["item1", "item2"]
优点: 简单灵活,易于理解。
使用 Flask 的 after_request 钩子
全局拦截所有响应,自动格式化。
from flask import Flask, jsonify, Response
import json
app = Flask(__name__)
@app.after_request
def format_response(response):
"""统一格式化所有响应"""
# 如果已经是JSON格式,进行包装
if response.is_json:
original_data = response.get_json()
# 避免二次包装(比如错误页面已经是JSON)
if "code" not in original_data:
formatted = {
"code": response.status_code,
"message": "success",
"data": original_data
}
response.set_data(json.dumps(formatted))
# 如果是HTML或其他格式,可以设置错误响应
elif response.status_code >= 400:
formatted = {
"code": response.status_code,
"message": response.status,
"data": None
}
response.set_data(json.dumps(formatted))
response.content_type = 'application/json'
return response
@app.route('/user')
def get_user():
# 直接返回字典,会被jsonify自动转JSON
return {"name": "Bob", "age": 25}
@app.route('/error')
def trigger_error():
# 404错误页面也会被统一格式化
abort(404)
优点: 全局生效,无需每个视图函数都调用封装函数。
使用 FastAPI 和 Pydantic 模型
FastAPI 天然支持响应模型,这是最优雅、类型安全的方式。
from fastapi import FastAPI, HTTPException
from pydantic import BaseModel
from typing import Any, Generic, TypeVar, Optional
app = FastAPI()
# 定义泛型响应模型
DataT = TypeVar('DataT')
class Response(BaseModel, Generic[DataT]):
code: int = 200
message: str = "success"
data: Optional[DataT] = None
# 成功响应的快捷方式
def success(data: Any = None):
return Response(code=200, message="success", data=data)
def error(message: str = "error", code: int = 400):
# 注意:抛出HTTPException,而不是直接返回
raise HTTPException(status_code=code, detail=Response(code=code, message=message, data=None).model_dump())
@app.get("/user/{user_id}", response_model=Response)
async def get_user(user_id: int):
if user_id == 1:
# 直接返回数据,FastAPI会根据response_model自动包装
return {"code": 200, "message": "success", "data": {"name": "Charlie", "age": 28}}
else:
return error(message="User not found", code=404)
# 更简便的方式:使用response_model_exclude_unset
@app.post("/create", response_model=Response[dict])
async def create_user(name: str, age: int):
return success(data={"id": 123, "name": name, "age": age})
# 全局异常处理器
@app.exception_handler(HTTPException)
async def http_exception_handler(request, exc):
return Response(
code=exc.status_code,
message=exc.detail.get("message", "error"),
data=None
)
优点: 类型安全、文档自动生成(Swagger UI)、Pydantic验证。
使用第三方库
- Flask-RESTful 的
marshal_with装饰器 - marshmallow 的
Schema - FastAPI 自带的
response_model
关键设计原则
- 统一状态码:建议使用业务状态码(如 20000, 40001)而非 HTTP 状态码(400, 500)。
- 区分成功和失败:失败时
data可以为 null 或包含错误详情。 - 避免混合格式:所有 API 响应都应该是 JSON 格式。
- 异常处理:在全局异常处理器中捕获未处理的异常,返回统一格式的错误响应。
示例:完整的企业级响应格式
{
"code": 20000,
"message": "success",
"data": {
"list": [],
"total": 0
},
"timestamp": 1700000000,
"path": "/api/v1/users"
}
- 小型项目:使用方案一(封装函数)或方案三(FastAPI+BaeModel)。
- 大型项目:推荐方案二(Flask
after_request)或方案三(FastAPI 泛型模型)。 - 最佳实践:始终定义一个
BaseResponse类,所有响应都基于它构建。
选择哪种方式取决于你的框架和项目复杂度,核心是一致性和可维护性。
版权声明:NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播