首页
/ FastAPI 响应状态码详解:声明、使用与动态修改 HTTP 状态码

FastAPI 响应状态码详解:声明、使用与动态修改 HTTP 状态码

2026-09-06 13:10:38作者:秋泉律Samson

本篇技术指南围绕 FastAPI 中 status_code 参数展开,讲解如何在路径操作(path operation)中声明 HTTP 响应状态码、理解各状态码区间的语义、使用 fastapi.status 常量替代裸数字,以及如何在运行时通过 Response 参数动态改变响应状态码。读完后你将能够正确地为接口配置响应状态码,理解 FastAPI 对"无 Body 状态码"的底层校验机制,并掌握状态码声明值与运行时实际返回值之间的协作关系。

OpenAPI 文档界面中 201 状态码的展示

在路径操作中声明 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 会做两件事:

  1. 在响应中返回该状态码——客户端收到的 HTTP 响应将携带这个状态码;
  2. 在 OpenAPI Schema 中如实记录该状态码,并因此在 Swagger UI 等文档界面中展示出来(如上文配图所示,POST /items/ 的响应标注为 201)。

无 Body 状态码的底层校验

部分 HTTP 状态码本身就规定了响应不允许携带 Body(例如 1XX 信息类状态码、204 No Content304 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.statusfastapi.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.pystatus_codesolved_result.response.status_code 的合并处理)。另外,Response 参数也可以声明在依赖项中并在依赖里设置状态码,但需要注意:最后被设置的值生效

声明值与运行时值的分工

  • 装饰器上的 status_code:设定默认状态码,并决定 OpenAPI 文档中"主响应"的记录;
  • 运行时 response.status_code:针对具体请求动态覆盖默认值;
  • 需要文档化多种可能状态(如同时声明 200404 的响应模型),应使用 responses 参数,详见 additional status codes 相关进阶内容。

验证与测试

仓库为这一功能提供了完整的教学示例测试:test_tutorial001_tutorial002.py,它同时覆盖裸数字 201status.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 的状态码(如 2043041XX)会被 is_body_allowed_for_status_codefastapi/utils.py)严格校验,声明与文档保持一致;
  • fastapi.status.HTTP_* 常量(源自 Starlette)替代裸数字,获得语义可读性与自动补全;
  • 需要按请求动态调整状态码时,在函数或依赖中注入 Response 参数并设置其 status_code,最后设置的值生效。
登录后查看全文
热门项目推荐
相关项目推荐