Python案例怎么统一返回数据格式?

wen python案例 30

本文目录导读:

Python案例怎么统一返回数据格式?

  1. 核心思想
  2. 方案一:使用 Flask 的 jsonify 封装函数
  3. 方案二:使用 Flask 的 after_request 钩子
  4. 方案三:使用 FastAPI 和 Pydantic 模型
  5. 方案四:使用第三方库
  6. 关键设计原则
  7. 示例:完整的企业级响应格式

在Python Web开发中(尤其是使用Flask、FastAPI等框架时),统一返回数据格式是一个非常常见的需求,它能确保前端调用API时,无论成功或失败,都能按照固定的结构解析数据。

下面我会介绍几种主流方案,以FlaskFastAPI为例。

核心思想

定义一个标准的响应体结构,通常包含:

{
  "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-RESTfulmarshal_with 装饰器
  • marshmallowSchema
  • FastAPI 自带的 response_model

关键设计原则

  1. 统一状态码:建议使用业务状态码(如 20000, 40001)而非 HTTP 状态码(400, 500)。
  2. 区分成功和失败:失败时 data 可以为 null 或包含错误详情。
  3. 避免混合格式:所有 API 响应都应该是 JSON 格式。
  4. 异常处理:在全局异常处理器中捕获未处理的异常,返回统一格式的错误响应。

示例:完整的企业级响应格式

{
  "code": 20000,
  "message": "success",
  "data": {
    "list": [],
    "total": 0
  },
  "timestamp": 1700000000,
  "path": "/api/v1/users"
}
  • 小型项目:使用方案一(封装函数)或方案三(FastAPI+BaeModel)。
  • 大型项目:推荐方案二(Flask after_request)或方案三(FastAPI 泛型模型)。
  • 最佳实践:始终定义一个 BaseResponse 类,所有响应都基于它构建。

选择哪种方式取决于你的框架和项目复杂度,核心是一致性和可维护性

抱歉,评论功能暂时关闭!