news 2026/9/9 23:40:17

FastAPI 附加状态码(Additional Status Codes):在同一路径操作中返回 200 与 201

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
FastAPI 附加状态码(Additional Status Codes):在同一路径操作中返回 200 与 201

FastAPI 附加状态码(Additional Status Codes):在同一路径操作中返回 200 与 201

【免费下载链接】fastapiFastAPI framework, high performance, easy to learn, fast to code, ready for production项目地址: https://gitcode.com/GitHub_Trending/fa/fastapi

在 FastAPI 中,路径操作(path operation)默认统一返回JSONResponse,并使用默认状态码或你在装饰器中显式设置的status_code。但在真实业务中,"更新或创建"(upsert)这类接口往往需要在一个端点里同时返回 200 "OK"(更新已有资源)与 201 "Created"(新建资源)。本指南以 FastAPI 官方进阶文档"Additional Status Codes"为核心,讲解如何通过直接返回Response(如JSONResponse)来附加状态码,并深入仓库源码与测试用例,说明其底层行为、注意事项以及如何与 OpenAPI 文档配合。

默认行为:一个路径操作只能有一个主状态码

默认情况下,FastAPI会使用JSONResponse返回响应,并将你在路径操作中返回的内容放入该JSONResponse中。状态码取自以下二者之一:

  • 默认状态码(未指定时为 200 "OK");
  • 你在路径操作装饰器中通过status_code参数显式设置的状态码。

从源码看,路由层会在响应序列化阶段统一处理状态码:routing.py 中根据显式传入的status_code或依赖解析结果来决定最终的响应状态码;若未设置则使用默认值 200。这也意味着:单个路径操作在"主状态码"层面只能有一个值

附加状态码:直接返回 Response

如果你想在返回主状态码之外,还返回其他状态码,可以通过直接返回一个Response对象(例如JSONResponse)来实现,并在构造时直接指定status_code

典型场景:假设你有一个允许"更新"条目的路径操作,成功时返回 200 "OK";同时你还希望它接受新条目——当条目之前不存在时,创建它并返回 201 "Created"。

完整示例(官方教程代码)

以下代码来自仓库中的 docs_src/additional_status_codes/tutorial001_an_py310.py,演示了 upsert 语义:

from typing import Annotated from fastapi import Body, FastAPI, status from fastapi.responses import JSONResponse app = FastAPI() items = {"foo": {"name": "Fighters", "size": 6}, "bar": {"name": "Tenders", "size": 3}} @app.put("/items/{item_id}") async def upsert_item( item_id: str, name: Annotated[str | None, Body()] = None, size: Annotated[int | None, Body()] = None, ): if item_id in items: item = items[item_id] item["name"] = name item["size"] = size return item else: item = {"name": name, "size": size} items[item_id] = item return JSONResponse(status_code=status.HTTP_201_CREATED, content=item)

仓库同时提供了不使用Annotated的等价版本:tutorial001_py310.py,其请求体参数写作name: str | None = Body(default=None),业务逻辑完全一致。

代码要点解析:

  • item_id已存在于items中(如"foo""bar"),走更新分支,直接返回字典item,由 FastAPI 默认的JSONResponse序列化,状态码为 200;
  • item_id不存在(如"red"),走创建分支,手动构造JSONResponse,设置status_code=status.HTTP_201_CREATED(即 201)并指定content=item作为响应体;
  • status.HTTP_201_CREATED来自fastapi.status,比硬编码数字 201 更可读、更不易出错。

测试用例验证

仓库在 tests/test_tutorial/test_additional_status_codes/test_tutorial001.py 中为上述两个教程版本提供了完整的测试,用TestClient直接验证两种状态码路径:

def test_update(client: TestClient): response = client.put("/items/foo", json={"name": "Wrestlers"}) assert response.status_code == 200, response.text assert response.json() == {"name": "Wrestlers", "size": None} def test_create(client: TestClient): response = client.put("/items/red", json={"name": "Chillies"}) assert response.status_code == 201, response.text assert response.json() == {"name": "Chillies", "size": None}

其中test_update验证更新已有条目返回 200,test_create验证新建条目返回 201,且两者响应体内容都符合预期。该测试以参数化方式同时覆盖tutorial001_py310tutorial001_an_py310两个版本(needs_py310标记要求 Python 3.10+)。

关键警告:直接返回 Response 不会被序列化

当你像上面的例子一样直接返回一个Response时,它会原样返回

  • 不会经过响应模型(response model)等机制的序列化处理;
  • 使用JSONResponse时,请确保content中的数据正是你想要返回的内容,并且值都是合法的 JSON。

这与返回普通 Python 对象(字典、Pydantic 模型等)的路径不同——后者会由 FastAPI 在内部序列化并应用过滤/校验逻辑。直接返回Response相当于把"响应构造"的控制权完全交给了你。

技术细节:fastapi.responses 与 starlette.responses

你也可以使用from starlette.responses import JSONResponse

FastAPI提供与starlette.responses相同的fastapi.responses命名空间,仅仅是出于方便开发者的考虑——大多数可用的响应类(JSONResponseHTMLResponsePlainTextResponseRedirectResponseStreamingResponseFileResponse等)都直接来自 Starlette,status模块也是如此。

从源码看,fastapi/responses.py 中的核心响应类都是对 Starlette 同名类的直接再导出(re-export),例如:

from starlette.responses import JSONResponse as JSONResponse # noqa from starlette.responses import Response as Response # noqa from starlette.responses import HTMLResponse as HTMLResponse # noqa

另外注意:该文件中的UJSONResponseORJSONResponse已被标记为deprecated(弃用),注释明确说明"FastAPI now serializes data directly to JSON"——即 FastAPI 现在直接序列化数据为 JSON,不再需要这两个高性能响应类。因此在新代码中应直接使用JSONResponse

附加状态码与 OpenAPI / API 文档的关系

如果你直接返回附加状态码和Response,它们不会被包含在 OpenAPI schema(即 API 文档)中,因为 FastAPI 没有办法提前知道你将要返回什么内容——它无法静态分析出代码分支中手动构造的JSONResponse及其状态码。

但这并不意味着无法文档化:你可以使用Additional Responses(附加响应)机制,在代码中为这些额外的状态码声明对应的响应模型与描述,使其出现在 OpenAPI 与交互式文档中。FastAPI 官方进阶文档《Additional Responses》专门讲解了这一主题。

两种机制的定位总结如下:

场景推荐做法
运行时返回非主状态码的响应体直接返回JSONResponse(status_code=..., content=...)
让附加状态码出现在 OpenAPI/API 文档中在路径操作装饰器中使用responses参数声明附加响应

两者可以组合使用:运行时用JSONResponse返回实际数据,装饰器中用responses声明文档,实现"行为与文档兼备"。

小结

  • 一个路径操作的"主状态码"通过装饰器status_code或默认值确定;
  • 需要在同一端点返回附加状态码时,直接返回JSONResponseResponse对象并设置status_code即可,这是官方推荐且最直接的方式;
  • 直接返回的Response不经过模型序列化,请自行确保content是合法 JSON 且包含所需数据;
  • 手动返回的附加状态码不会自动进入 OpenAPI schema,如需文档化请配合responses参数声明附加响应;
  • 本教程对应源码位于 docs_src/additional_status_codes/,测试位于 tests/test_tutorial/test_additional_status_codes/,可用于对照学习与验证。

【免费下载链接】fastapiFastAPI framework, high performance, easy to learn, fast to code, ready for production项目地址: https://gitcode.com/GitHub_Trending/fa/fastapi

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/9 23:39:49

分布式事务实战:解冻支付场景下的TCC、幂等与最终一致性设计

先讲一个我凌晨两点被电话叫醒的案子。监控群里连续刷出十几条资金流水不平的告警,客服那边也炸了锅,有用户说订单取消了但钱一直没回来,另一拨人却反馈钱退了但订单还卡在支付中不敢动。两个方向上看起来完全相反的问题,最后都指…

作者头像 李华
网站建设 2026/9/9 23:39:39

STM32 IAP实战:YMODEM协议Bootloader设计与跳转卡死排查

简介:面向STM32嵌入式开发者的IAP Bootloader实践资料,基于YModem协议实现串口在线升级方案,完整覆盖bootloader启动、数据接收、CRC校验、Flash写入及跳转APP的关键流程。压缩包共475个文件,以C语言源码、头文件、编译生成的.o/.…

作者头像 李华
网站建设 2026/9/9 23:34:24

grblHAL入门:从AVR到STM32/RP2040的移植实战与源码解析

简介:grbl是CNC领域广泛使用的开源运动控制固件,但原生版本主要运行于8位AVR平台,性能与外设扩展受限。grblHAL是其1.1f版本的HALified移植分支,专门面向ESP32、STM32、MSP432、LPC17xx、SAMD21、TM4C等32位处理器,解决…

作者头像 李华