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 返回可解析的时间字符串,并带自定义响应头。
三种输出方式怎么选
- 返回字典:入门最简单,框架自动生成 JSON。
- 返回模型并声明
response_model:形成清楚的输出契约,支持校验、过滤和文档。 - 直接返回
JSONResponse:需要自行控制响应对象时使用,正文必须已经是 JSON 可编码的数据。
直接返回 Response 子类时,会绕过通常的响应模型处理流程,不要依赖它继续帮你过滤密码字段。datetime、UUID、Decimal、ORM 对象等应按模型或编码器规则处理。
常见错误
- 先
json.dumps(data)再把字符串作为普通返回值,会造成二次编码,客户端可能拿到 JSON 字符串而不是对象。 JSONResponse(content={"time": datetime.now()})不能假设自动处理所有 Python 类型。None一般序列化为 JSONnull;204 响应则应没有正文。- 输入错误和服务端响应错误不同。声明输出字段为整数却返回不可转换的文本,属于服务端违反契约,通常产生 500,需要修复代码。
状态码与错误格式
创建资源可使用 @app.post(..., status_code=201);已知业务错误通过 HTTPException 明确表达。统一错误格式时需保留真实 HTTP 状态码,不能所有失败都返回 200,否则监控和客户端重试判断会受影响。
练习:为用户模型加可选头像地址,测试空值序列化;添加自定义响应头,使用 curl.exe -i 观察正文与响应头各自在哪里。