首页
/ FastAPI 直接返回 Response:JSONResponse、jsonable_encoder 与自定义响应实践指南

FastAPI 直接返回 Response:JSONResponse、jsonable_encoder 与自定义响应实践指南

2026-09-07 16:14:18作者:翟萌耘Ralph

本文围绕 FastAPI 官方文档《レスポンスを直接返す》(docs/ja/docs/advanced/response-directly.md)展开,讲解如何在 path operation 中直接返回 Response 对象:何时应该直接构造 JSONResponse、如何用 jsonable_encoder 把 Pydantic 模型等数据转换为 JSON 兼容内容、以及如何返回 XML 等完全自定义的响应。读完本文,你将理解 FastAPI 对「返回普通数据」与「返回 Response」两条链路的处理差异,并能结合 fastapi/routing.py 的源码判断自己项目应该走哪条路径。

FastAPI 的默认响应处理方式

创建 FastAPIpath operation 时,通常可以返回任意数据:dictlist、Pydantic 模型、数据库模型等。默认情况下,FastAPI 会按以下规则处理返回值:

  • 声明了 Response Modelresponse_model 参数或返回类型注解)时,FastAPI 使用 Pydantic 将数据序列化为 JSON;
  • 未声明 Response Model 时,FastAPI 使用 JSON 兼容编码器 中介绍的 jsonable_encoder 把数据转换后,放入 JSONResponse 返回;
  • 当然,你也可以直接构造一个 JSONResponse 并返回。

性能提示:通常使用 Response Model 比直接返回 JSONResponse 性能要好得多,因为声明 Response Model 后数据由 Pydantic 在 Rust 层完成序列化。

源码视角:返回普通数据时的处理路径

从源码结构看,上述「未声明 Response Model 时走 jsonable_encoder + JSONResponse」的路径可以在 fastapi/routing.py 中得到印证:当 path operation 的返回值不是 Response 实例时,FastAPI 会调用 serialize_response(内部走 jsonable_encoder)完成转换,再用实际注册的 response class(默认为 JSONResponse)包装内容;而当 response_field 存在(即声明了返回类型或 response model)且未设置自定义 response class 时,源码会启用 use_dump_json 快速路径——由 Pydantic 的 Rust 核心直接生成 JSON 字节流,跳过「中间 Python dict + json.dumps()」这一步,最终直接构造一个 media_type="application/json"Response 返回(见 fastapi/routing.py 处的注释与实现)。

直接返回 Response

你可以返回 Response 或它的任何子类。

注意:JSONResponse 本身就是 Response 的子类。

当返回值是 Response 实例时,FastAPI 会直接把它透传出去

  • 不会用 Pydantic 模型做任何数据转换;
  • 不会把内容转换为任何类型;
  • 不会执行 Response Model 声明的校验与过滤。

这一点在 fastapi/routing.py 中体现得非常直接:

if isinstance(raw_response, Response):
    if raw_response.background is None:
        raw_response.background = solved_result.background_tasks
    response = raw_response

也就是说,返回值是 Response 时唯一的"干预",只是在响应没有设置 background 时补上依赖中解析出的后台任务。

这种透传带来两方面的影响:

  • 灵活性:可以返回任意数据格式、覆盖任何数据声明或校验;
  • 责任:返回的数据是否正确、格式是否正确、能否被序列化,都由你自己保证。

Response 中使用 jsonable_encoder

由于 FastAPI 不会对你返回的 Response 做任何修改,你必须确保其内容已经是"可发送"的状态。

例如,不能把一个 Pydantic 模型直接塞进 JSONResponse——必须先把它转换成 dict,且其中所有数据类型(如 datetimeUUID 等)都必须是 JSON 兼容类型。此时可以在把数据交给响应之前,用 jsonable_encoder 做转换:

from datetime import datetime

from fastapi import FastAPI
from fastapi.encoders import jsonable_encoder
from fastapi.responses import JSONResponse
from pydantic import BaseModel


class Item(BaseModel):
    title: str
    timestamp: datetime
    description: str | None = None


app = FastAPI()


@app.put("/items/{id}")
def update_item(id: str, item: Item):
    json_compatible_item_data = jsonable_encoder(item)
    return JSONResponse(content=json_compatible_item_data)

完整示例见 docs_src/response_directly/tutorial001_py310.py

jsonable_encoder 能转换哪些类型

jsonable_encoder 定义于 fastapi/encoders.py,支持 include / exclude / by_alias / exclude_unset / exclude_defaults / exclude_none / custom_encoder 等参数,与 Pydantic 的字段过滤语义一致。从 ENCODERS_BY_TYPE 映射表 可以看到,它内置了针对 UUID: strSecretStr: strSecretBytes: strPath: strAnyUrl: strset: list 等类型的转换规则;datetime 则通过 str 转换。此外它也能处理 Pydantic 模型实例(转为 dict)、dataclass、任意对象(调用 __dict__)等。

技术细节:fastapi.responsesstarlette.responses

你同样可以 from starlette.responses import JSONResponse

FastAPI 只是出于开发者便利,把 starlette.responses 中的同名内容以 fastapi.responses 的形式再提供了一遍。可用的大多数响应类都直接来自 Starlette。从 fastapi/responses.py 可以看到,FileResponseHTMLResponseJSONResponsePlainTextResponseRedirectResponseResponseStreamingResponse 等全部是从 starlette.responses 直接 re-export 的;FastAPI 自身仅额外提供了 SSE 的 EventSourceResponse,以及已标记弃用的 UJSONResponse / ORJSONResponse(源码注释说明:当设置了返回类型或 response model 时,FastAPI 已能通过 Pydantic 直接序列化到 JSON 字节,更快且无需自定义响应类)。

返回自定义 Response

上面的示例展示了全部所需部件,但实用性有限——你完全可以直接返回 item,让 FastAPI 默认地帮你转成 dict 并包进 JSONResponse。直接返回 Response 真正的价值在于返回自定义格式的响应。

比如你想返回一个 XML 响应。可以把 XML 内容放进字符串,塞进 Response,设置对应的 media_type,然后返回:

from fastapi import FastAPI, Response

app = FastAPI()


@app.get("/legacy/")
def get_legacy_data():
    data = """<?xml version="1.0"?>
    <shampoo>
    <Header>
        Apply shampoo here.
    </Header>
    <Body>
        You'll have to use soap here.
    </Body>
    </shampoo>
    """
    return Response(content=data, media_type="application/xml")

完整示例见 docs_src/response_directly/tutorial002_py310.py。由于该返回值是 Response 实例,FastAPI 不会触碰 data 的内容,XML 会按原样发出,Content-Type 头为 application/xml。同样的思路可以扩展到 PDF、CSV、自定义二进制协议等场景。

Response Model 的工作机制

当你在 path operation 中声明 Response Model(返回类型) 时,FastAPI 会用 Pydantic 通过它把数据序列化为 JSON:

from fastapi import FastAPI
from pydantic import BaseModel

app = FastAPI()


class Item(BaseModel):
    name: str
    description: str | None = None
    price: float
    tax: float | None = None
    tags: list[str] = []


@app.post("/items/")
async def create_item(item: Item) -> Item:
    return item


@app.get("/items/")
async def read_items() -> list[Item]:
    return [
        Item(name="Portal Gun", price=42.0),
        Item(name="Plumbus", price=32.0),
    ]

完整示例见 docs_src/response_model/tutorial001_01_py310.py

因为序列化发生在 Rust 侧,性能远好于用常规 Python 加 JSONResponse 类的做法。使用 response_model 或返回类型时,FastAPI 不会使用 jsonable_encoder 转换数据(那会更慢),也不会使用 JSONResponse 类。取而代之的是:它直接取 Pydantic 用 response model(或返回类型)生成的 JSON 字节,返回一个携带正确 JSON 媒体类型(application/json)的 Response。这与 fastapi/routing.py 中的 use_dump_json 快速路径完全对应。

备注:直接返回 Response 的边界

直接返回 Response 时:

  • 数据不会被校验;
  • 不会被转换(序列化);
  • 不会被自动写入 OpenAPI 文档。

不过你仍然可以按照 OpenAPI 中的 Additional Responses 所描述的方式,手动为这些响应编写文档。后续章节(Custom Response、Response Class 等)会介绍如何在继续自动数据转换与文档生成的同时使用/声明这些自定义 Response

小结:如何选型

场景 推荐做法 原因
常规 JSON API 声明 Response Model 或返回类型 Pydantic Rust 层序列化,性能最好,且自动校验、过滤、生成文档
需要控制 JSON 内容(如 exclude、自定义头)但不想用 response model jsonable_encoder + JSONResponse FastAPI 不干预,你自己掌控输出
返回 XML / PDF / 其他非 JSON 格式 Response(content=..., media_type=...) 或对应子类 直接透传,任意 media_type
性能敏感的高频 JSON 端点 优先 Response Model 避免 jsonable_encoder 的 Python 侧开销

核心原则一句话概括:FastAPI 只透传 Response,其余都帮你做;透传的自由度换来了序列化、校验与文档的全部责任

登录后查看全文
热门项目推荐
相关项目推荐

项目优选

收起
kernelkernel
deepin linux kernel
C
33
18
ops-transformerops-transformer
本项目是CANN提供的transformer类大模型算子库,实现网络在NPU上加速计算。
C++
1.13 K
2.75 K
pytorchpytorch
作为 Ascend for PyTorch 社区的核心组件,TorchNPU 是昇腾专为 PyTorch 打造的深度学习适配插件,使 PyTorch 框架能够直接调用昇腾 NPU,为开发者提供昇腾 AI 处理器的超强算力。
Python
857
1.35 K
docsdocs
暂无描述
Markdown
897
5.8 K
kernelkernel
openEuler内核是openEuler操作系统的核心,既是系统性能与稳定性的基石,也是连接处理器、设备与服务的桥梁。
C
529
593
ops-nnops-nn
本项目是CANN提供的神经网络类计算算子库,实现网络在NPU上加速计算。
C++
915
1.83 K
jiuwenswarmjiuwenswarm
JiuwenSwarm 是一款基于openJiuwen开发的智能AI Agent,它能够将大语言模型的强大能力,通过你日常使用的各类通讯应用,直接延伸至你的指尖。
Python
3.58 K
1.01 K
ops-mathops-math
本项目是CANN提供的数学类基础计算算子库,实现网络在NPU上加速计算。
C++
1.35 K
1.46 K
cann-learning-hubcann-learning-hub
CANN 学习中心仓,支持在线互动运行、边学边练,提供教程、示例与优化方案,一站式助力昇腾开发者快速上手。
Jupyter Notebook
1.01 K
515
AscendNPU-IRAscendNPU-IR
AscendNPU-IR是基于MLIR(Multi-Level Intermediate Representation)构建的,面向昇腾亲和算子编译时使用的中间表示,提供昇腾完备表达能力,通过编译优化提升昇腾AI处理器计算效率,支持通过生态框架使能昇腾AI处理器与深度调优
C++
547
388