FastAPI 响应状态码详解:声明、使用与动态修改 HTTP 状态码
本篇技术指南围绕 FastAPI 中 status_code 参数展开,讲解如何在路径操作(path operation)中声明 HTTP 响应状态码、理解各状态码区间的语义、使用 fastapi.status 常量替代裸数字,以及如何在运行时通过 Response 参数动态改变响应状态码。读完后你将能够正确地为接口配置响应状态码,理解 FastAPI 对"无 Body 状态码"的底层校验机制,并掌握状态码声明值与运行时实际返回值之间的协作关系。
在路径操作中声明 status_code
与指定响应模型(response_model)类似,你可以在任意路径操作装饰器中通过 status_code 参数声明该接口响应的 HTTP 状态码:
@app.get()@app.post()@app.put()@app.delete()- 等等
仓库中的官方示例(tutorial001_py310.py):
from fastapi import FastAPI
app = FastAPI()
@app.post("/items/", status_code=201)
async def create_item(name: str):
return {"name": name}
这里有两点需要注意:
status_code 是装饰器方法的参数,而不是路径操作函数的参数。 查询参数、请求体等都声明在 create_item 函数签名中,但 status_code 声明在 @app.post(...) 这一层。如果把 status_code 误写进函数签名,它会被当作一个普通的请求参数处理,状态码也就不会被设置。
status_code 接收的是一个表示 HTTP 状态码的数字,同时也可以接收一个 IntEnum,例如 Python 标准库中的 http.HTTPStatus。这一点在源码中可以直接印证:在 fastapi/routing.py 中,路由构建逻辑会对枚举值做归一化处理:
# normalize enums e.g. http.HTTPStatus
if isinstance(status_code, IntEnum):
status_code = int(status_code)
route.status_code = status_code
也就是说,无论是 201 还是 http.HTTPStatus.CREATED,最终都会归一化为整数后保存到路由对象上。
status_code 的两大效果:响应与 OpenAPI 文档
声明 status_code 之后,FastAPI 会做两件事:
- 在响应中返回该状态码——客户端收到的 HTTP 响应将携带这个状态码;
- 在 OpenAPI Schema 中如实记录该状态码,并因此在 Swagger UI 等文档界面中展示出来(如上文配图所示,
POST /items/的响应标注为 201)。
无 Body 状态码的底层校验
部分 HTTP 状态码本身就规定了响应不允许携带 Body(例如 1XX 信息类状态码、204 No Content、304 Not Modified)。FastAPI 对此有专门的认知,会生成"该响应没有 Body"的 OpenAPI 文档,并且在声明层面就进行强校验。
校验工具函数定义在 fastapi/utils.py:
def is_body_allowed_for_status_code(status_code: int | str | None) -> bool:
if status_code is None:
return True
# Ref: OpenAPI 3.1 规范中 patterned-fields-1 一节
if status_code in {
"default",
"1XX",
"2XX",
"3XX",
...
在路由构建阶段(fastapi/routing.py),如果你声明了 response_model 却同时使用了一个不允许 Body 的状态码,会直接触发断言失败:
if route.response_model:
assert is_body_allowed_for_status_code(status_code), (
f"Status code {status_code} must not have a response body"
)
同样的校验也应用于 responses 参数中声明的附加响应模型(见 fastapi/routing.py)。在请求处理阶段,响应序列化前还会再次检查:如果状态码不允许 Body,FastAPI 就不会把返回数据写入响应体。这种"声明即约束"的设计让 API 文档与实际行为保持一致。
HTTP 状态码速查:五个区间的语义
HTTP 响应中会附带一个三位数字的状态码。这些状态码有对应的名称方便识别,但真正起作用的是数字本身。简要归纳如下:
| 区间 | 含义 | 使用频率与说明 |
|---|---|---|
100 - 199 |
Information(信息) | 极少直接使用,响应不允许有 Body |
200 - 299 |
Successful(成功) | 使用最多。200 是默认状态码,表示一切"OK";201 Created 通常用于在数据库创建了新记录之后;特殊情况 204 No Content 表示没有内容要返回给客户端,因此响应必须没有 Body |
300 - 399 |
Redirection(重定向) | 可能有也可能没有 Body,但 304 Not Modified 必须没有 Body |
400 - 499 |
Client Error(客户端错误) | 第二常用。404 Not Found 用于资源不存在;客户端的通用错误可以直接用 400 |
500 - 599 |
Server Error(服务器错误) | 几乎从不直接使用。当应用代码或服务器某处出错时,会自动返回这些状态码之一 |
如需了解每个状态码的具体语义,可以参考 MDN 关于 HTTP 状态码的文档。
用 fastapi.status 常量代替裸数字
回到前面的示例(tutorial001_py310.py):
@app.post("/items/", status_code=201)
201 表示 "Created"。但你不必去记忆每一个状态码数字代表什么——可以使用 fastapi.status 提供的便捷变量。改进后的写法见 tutorial002_py310.py:
from fastapi import FastAPI, status
app = FastAPI()
@app.post("/items/", status_code=status.HTTP_201_CREATED)
async def create_item(name: str):
return {"name": name}
这些常量本质上就是同样的数字,纯作为开发便捷设施存在,但它们带来两个实际好处:
- 语义自文档化:
HTTP_201_CREATED直接表达了意图,而201需要读者自行回忆; - 编辑器自动补全:输入
status.HTTP_后,编辑器可以列出全部状态码常量及其含义,无需查表。
技术细节:常量来自 Starlette
在 fastapi/__init__.py 中可以看到,fastapi.status 实际上就是 Starlette 的 re-export:
from starlette import status as status
也就是说,你也可以 from starlette import status,两者完全等价。FastAPI 只是把 starlette.status 以 fastapi.status 的名字再暴露一次,纯粹是为开发者提供便利。
运行时动态改变状态码:Response 参数
在 Response - Change Status Code 进阶指南中,你会看到如何返回不同于此处声明的默认值的状态码。
典型场景:接口默认返回 200 OK;但如果数据不存在、需要现场创建,则返回 201 Created。此时你希望按请求结果动态选择状态码,同时仍保留 response_model 对返回数据的过滤与转换能力。
做法是在路径操作函数中声明一个类型为 Response 的参数(与声明 Cookie、Headers 参数的方式相同),然后在函数体内直接修改这个"临时"响应对象的 status_code:
@app.put("/items/{item_id}")
async def read_item(item_id: str, response: Response):
if not item_id.startswith("foo"):
response.status_code = 400
return {"item_id": item_id}
对应的官方示例代码在 tutorial001_py310.py。此时函数仍然按常规方式返回任意对象(dict、数据库模型等),如果声明了 response_model,它依旧会用来过滤和转换返回对象;FastAPI 会从这个"临时"响应对象中提取状态码(以及 Cookie 和 Headers),再合并进最终携带返回数据的响应。
这一机制在源码中同样可以验证:请求处理完成后的响应组装逻辑会优先采用 Response 参数上被设置的状态码,覆盖路由声明的默认值(见 fastapi/routing.py 中 status_code 与 solved_result.response.status_code 的合并处理)。另外,Response 参数也可以声明在依赖项中并在依赖里设置状态码,但需要注意:最后被设置的值生效。
声明值与运行时值的分工
- 装饰器上的
status_code:设定默认状态码,并决定 OpenAPI 文档中"主响应"的记录; - 运行时
response.status_code:针对具体请求动态覆盖默认值; - 需要文档化多种可能状态(如同时声明
200与404的响应模型),应使用responses参数,详见 additional status codes 相关进阶内容。
验证与测试
仓库为这一功能提供了完整的教学示例测试:test_tutorial001_tutorial002.py,它同时覆盖裸数字 201 与 status.HTTP_201_CREATED 两种写法,验证两种形式产生的行为一致。相关的示例源码均位于 docs_src/response_status_code/ 目录下,可直接复制运行(需已安装 FastAPI),例如:
uvicorn docs_src.response_status_code.tutorial001_py310:app
启动后访问 /docs,即可在 OpenAPI 界面中确认 POST /items/ 的响应状态码已记录为 201。
小结
status_code声明在装饰器方法上,接收整数或IntEnum(如http.HTTPStatus),源码会统一归一化为整数(fastapi/routing.py);- 它既决定实际响应携带的状态码,也决定 OpenAPI Schema 中的记录;
- 不允许 Body 的状态码(如
204、304、1XX)会被is_body_allowed_for_status_code(fastapi/utils.py)严格校验,声明与文档保持一致; - 用
fastapi.status.HTTP_*常量(源自 Starlette)替代裸数字,获得语义可读性与自动补全; - 需要按请求动态调整状态码时,在函数或依赖中注入
Response参数并设置其status_code,最后设置的值生效。
atomcodeClaude Code 的开源替代方案。连接任意大模型,编辑代码,运行命令,自动验证 — 全自动执行。用 Rust 构建,极致性能。 | An open-source alternative to Claude Code. Connect any LLM, edit code, run commands, and verify changes — autonomously. Built in Rust for speed. Get StartedRust0624
Hy4-previewHy4 preview 是由腾讯混元团队研发的新一代混合专家(MoE)旗舰模型。模型总参数量 770B,每个 token 激活 49B,主干共包含78层,第一层采用标准 FFN,其余 77 层均为 MoE 结构,每层包含 256 个路由专家与 1 个共享专家,每个 token 激活 top-8 路由专家及共享专家。主干之外原生内置 1 层 MTP(总参数量 10B,激活 0.7B)以支持投机解码。Python00
GLM-5.3GLM-5.3 与 GLM-5.2 使用相同的基座模型——所有提升均来自后训练。与 GLM-5.2 相比,它在复杂编程和长程任务上的表现显著提升。Jinja00
GLM-5.3-FlashGLM-5.3-Flash (320B-A18B),是GLM-5系列的首个原生多模态模型。320B总参数,能力超过GLM-5.2Jinja00
Spark-X2.5-4BSpark-X2.5-4B 旨在让强大的 AI 更实用、更高效、更易获得。在广泛日常任务中表现强劲,涵盖对话、写作、翻译、推理、编码、工具调用以及智能体工作流,并在同等规模的开源模型中取得领先成绩。Spark-X2.5 将面向效率的架构与最高 1M tokens 的原生上下文窗口相结合,并支持 200 多种语言。Python00
Spark-X2.5-1.7BSpark-X2.5-1.7B 旨在让强大的 AI 更加实用、高效且易于获取。这些模型在广泛的日常任务中表现出色,涵盖对话、写作、翻译、推理、编程、工具调用和智能体工作流,并在同等规模的开源模型中取得领先结果。Spark-X2.5 将面向效率的架构与最高 1M tokens 的原生上下文窗口相结合,并支持 200 多种语言。Python00
