Skip to content

14. FastAPI 响应类型_JSON格式 ​

JSON 响应是最常用的 API 输出 ​

JSON 是交换格式,不是 Python 对象本身。路由返回字典或模型后,框架需要将其编码并生成 HTTP 响应。建议先确定“对外允许哪些字段”,再决定序列化方式。

python
from datetime import datetime, timezone
from fastapi import FastAPI
from fastapi.encoders import jsonable_encoder
from fastapi.responses import JSONResponse
from pydantic import BaseModel

app = FastAPI()

class UserOut(BaseModel):
    id: int
    name: str

@app.get("/users/1", response_model=UserOut)
def user_detail():
    return {"id": 1, "name": "小明", "password_hash": "不能公开"}

@app.get("/server-time")
def server_time():
    content = jsonable_encoder({"time": datetime.now(timezone.utc)})
    return JSONResponse(content=content, headers={"X-Service": "study"})

保存为 main.py,运行 uv run uvicorn main:app --reload。/users/1 只返回 id 和 name;/server-time 返回可解析的时间字符串,并带自定义响应头。

三种输出方式怎么选 ​

  1. 返回字典:入门最简单,框架自动生成 JSON。
  2. 返回模型并声明 response_model:形成清楚的输出契约,支持校验、过滤和文档。
  3. 直接返回 JSONResponse:需要自行控制响应对象时使用,正文必须已经是 JSON 可编码的数据。

直接返回 Response 子类时,会绕过通常的响应模型处理流程,不要依赖它继续帮你过滤密码字段。datetime、UUID、Decimal、ORM 对象等应按模型或编码器规则处理。

常见错误 ​

  • 先 json.dumps(data) 再把字符串作为普通返回值,会造成二次编码,客户端可能拿到 JSON 字符串而不是对象。
  • JSONResponse(content={"time": datetime.now()}) 不能假设自动处理所有 Python 类型。
  • None 一般序列化为 JSON null;204 响应则应没有正文。
  • 输入错误和服务端响应错误不同。声明输出字段为整数却返回不可转换的文本,属于服务端违反契约,通常产生 500,需要修复代码。

状态码与错误格式 ​

创建资源可使用 @app.post(..., status_code=201);已知业务错误通过 HTTPException 明确表达。统一错误格式时需保留真实 HTTP 状态码,不能所有失败都返回 200,否则监控和客户端重试判断会受影响。

练习:为用户模型加可选头像地址,测试空值序列化;添加自定义响应头,使用 curl.exe -i 观察正文与响应头各自在哪里。