首页
/ FastAPI Header 参数完全指南:声明、下划线自动转换与重复请求头的处理

FastAPI Header 参数完全指南:声明、下划线自动转换与重复请求头的处理

2026-09-07 13:02:03作者:卓艾滢Kingsley

Header(请求头/报头)参数用于从 HTTP 请求中提取元数据,例如 User-Agent、认证令牌 X-Token 或自定义扩展头。本指南以 docs/es/docs/tutorial/header-params.md(及对应的英文原版 docs/en/docs/tutorial/header-params.md)为核心脉络,结合 FastAPI 源码仓库中的真实实现与示例,系统讲解如何用 Header 声明请求头参数、FastAPI 如何自动把 Python 变量名的下划线转换为 HTTP 标准的连字符,以及如何接收出现多次的重复请求头。读完后,你将能在自己的 FastAPI 接口中正确、优雅地处理各类 HTTP 请求头,并理解其背后的运行机制。

Header 与 Query、Path、Cookie 的"家族关系"

FastAPI 允许你用与定义 QueryPathCookie 参数完全相同的方式定义 Header 参数。三者都用于从 HTTP 请求的不同位置取值:

  • Path:从 URL 路径中取值;
  • Query:从查询字符串(?key=value)中取值;
  • Cookie:从请求的 Cookie 中取值;
  • Header:从 HTTP 请求头中取值。

从源码可以印证这一"同族"关系:在 fastapi/params.py 中,HeaderParam 的子类,与 PathQueryCookie 等共享同一个基类,并通过 in_ = ParamTypes.header 指明其数据来源是 HTTP 请求头。

需要特别记住的一点是:当你 from fastapi import Header 后所拿到的 Header,实际上是一个函数而非类本身。在 fastapi/param_functions.py 中可以看到,Header() 等名字是返回特殊类实例的工厂函数。这也是为什么文档与源码中会出现 Header 这种"首字母大写、写法却像函数调用"的风格——日常使用中的 Header()Query()Path() 都是函数调用,它们在背后替你构造对应的参数声明对象。

提示:HTTP 请求头默认不会被当作 Query 参数解析。如果不使用 Header 来声明,FastAPI 会把普通函数参数误判为查询参数(从源码看,位于 fastapi/dependencies/utils.py 的默认逻辑是:当参数属于 Param 基类且未明确指定来源 in_ 时,一律归入 ParamTypes.query)。因此,声明请求头必须显式使用 Header

第一步:导入 Header

按照 FastAPI 官方教程(对应英文原版 Header Parameters),首先导入 Header

from typing import Annotated

from fastapi import FastAPI, Header

app = FastAPI()

第二步:声明 Header 参数

声明 header 参数的结构与 PathQueryCookie 完全一致:你可以设置默认值,也可以叠加所有额外的校验(gtgemin_lengthpattern 等)与标注参数(titledescriptiondeprecatedalias 等)。

仓库中的官方示例 docs_src/header_params/tutorial001_an_py310.py 演示了用 Annotated 语法声明一个可选的 user_agent 请求头:

from typing import Annotated

from fastapi import FastAPI, Header

app = FastAPI()


@app.get("/items/")
async def read_items(user_agent: Annotated[str | None, Header()] = None):
    return {"User-Agent": user_agent}

发送请求后,返回体中即可看到收到的 User-Agent 值:

$ curl http://127.0.0.1:8000/items/ -H "User-Agent: my-test-agent"
{"User-Agent":"my-test-agent"}

对于不使用 Annotated 的老式写法,FastAPI 也提供了兼容路径——同目录下的 docs_src/header_params/tutorial001_py310.py 展示了通过 Header(default=None) 直接指定默认值的方式:

from fastapi import FastAPI, Header

app = FastAPI()


@app.get("/items/")
async def read_items(user_agent: str | None = Header(default=None)):
    return {"User-Agent": user_agent}

两种写法在功能上等价;Annotated 是当前 FastAPI 官方文档推荐的首选方式,因为它把"类型"与"参数元数据"绑定在同一声明中,语义更清晰,也便于后续在类型层面做静态检查。

从实现层面看,fastapi/param_functions.pyHeader 函数提供的 convert_underscores 等关键字参数,本质上都会传递给 fastapi/params.pyHeader 类构造器,再经由统一的 Param 基类完成默认值、校验规则、别名等信息的组装,最终在依赖注入阶段被解析成真正的请求字段。

自动转换:下划线 _ 如何变成连字符 -

Header 相比 PathQueryCookie 多了一项独特能力——下划线到连字符的自动转换,这正是处理 HTTP 请求头时最容易踩坑也最实用的一环。

背景知识是这样的:绝大多数标准 HTTP 请求头都以连字符(hyphen,即减号 -)分隔单词,例如 User-AgentX-TokenAccept-Language。但在 Python 中,user-agent 这样的变量名是非法标识符——你无法写出 def read(user-agent: str) 这样的代码。

于是 FastAPI 默认提供了转换规则:把 Python 参数名中的下划线 _ 替换为连字符 -,再用于匹配真实的 HTTP 请求头。反过来,因为 HTTP 请求头本身不区分大小写,你可以放心用 Python 惯用的 snake_case(如 user_agent)声明参数,而不必刻意写成 User_AgentUser-Agent 这类大写形式。

也就是说,上面示例中的参数 user_agent 会被自动解释为请求头 User-Agent

转换发生在哪里?

这一逻辑落在请求解析与 OpenAPI 文档生成两个层面:

  1. 请求解析阶段:在 fastapi/dependencies/utils.py 中可以看到核心逻辑——只要该参数属于 Header 且没有显式指定 alias,并且 convert_underscores 为真,FastAPI 就会执行:

    alias = param_name.replace("_", "-")
    field_info.alias = alias
    

    即用"下划线替换成连字符"的结果作为真正从请求头中取值的别名。

  2. OpenAPI 文档生成阶段:在 fastapi/openapi/utils.py 附近,生成 API 文档时同样会遵循 convert_underscores 标志,用转换后的连字符名称记录请求头,保证 Swagger UI / ReDoc 中展示的 header 名与真实 HTTP 协议一致。

因此,"在 Python 代码里写 user_agent,在 HTTP 请求里发 User-Agent"这一双向心智模型是完全成立的,不需要你手动做任何大小写或连字符换算。

需要时关闭转换:convert_underscores=False

如果出于某些原因你必须原样保留下划线(例如某个非标准的自定义请求头本身就叫 strange_header,带下划线),可以把 Headerconvert_underscores 参数设为 False

官方示例 docs_src/header_params/tutorial002_an_py310.py 演示了这一用法:

from typing import Annotated

from fastapi import FastAPI, Header

app = FastAPI()


@app.get("/items/")
async def read_items(
    strange_header: Annotated[str | None, Header(convert_underscores=False)] = None,
):
    return {"strange_header": strange_header}

此时只有真正发送名为 strange_header(含下划线)的请求头才能取到值:

$ curl http://127.0.0.1:8000/items/ -H "strange_header: hello"
{"strange_header":"hello"}

如果关闭了转换却仍发送 Strange-Header(连字符形式),该参数将取不到内容。

关闭转换前必读的警告

FastAPI 官方文档特别提醒:在将 convert_underscores 设为 False 之前要三思。因为部分 HTTP 代理和服务器会拒绝或丢弃名称中带下划线的请求头——下划线头并非 HTTP 规范中的标准实践,一些中间件(如老旧的 WSGI 服务器、部分负载均衡器)会对它们做特殊处理甚至直接拦截。如果线上环境由这类代理/服务器把关,使用带下划线的请求头可能导致请求行为与本地开发不符。因此默认的连字符转换不仅是为了代码合法性,更是一种贴近真实 Web 部署环境的务实设计。

另外补充一个细节:仓库测试 tests/test_query_cookie_header_model_extra_params.py 中专门覆盖了"开启转换时优先匹配连字符头"与"关闭转换时拒绝下划线头"的行为,验证了 convert_underscores 在 Header 模型层面同样生效(含 Header(convert_underscores=False) 的用法)。这与教程中把该选项用在单参数声明上的方式是同一套机制在不同层级的体现。

处理重复的请求头:使用 list 类型

HTTP 协议允许同一个请求头出现多次,例如客户端连续发送两条 X-Token。FastAPI 支持这种"重复头(duplicate headers)"场景:只要把参数类型声明为 list,FastAPI 就会把重复头的所有值收集成一个 Python 列表

官方示例 docs_src/header_params/tutorial003_an_py310.py 演示了如何声明一个可能出现多次的 X-Token

from typing import Annotated

from fastapi import FastAPI, Header

app = FastAPI()


@app.get("/items/")
async def read_items(x_token: Annotated[list[str] | None, Header()] = None):
    return {"X-Token values": x_token}

向该接口同时发送两条 X-Token 请求头:

X-Token: foo
X-Token: bar

FastAPI 会返回(注意教程示例中列表内元素顺序是 "bar""foo",与请求发送顺序相反,这正是 HTTP 库/服务器底层合并重复头时的常见表现):

{
    "X-Token values": [
        "bar",
        "foo"
    ]
}

几点实战提示:

  • 若请求中只出现一次该头,你会得到只含一个元素的列表;若未发送该头且声明了默认值 None,则取值为 None
  • 类型标注可结合元素类型做进一步约束,例如 list[int] 会对每个值分别做类型转换与校验;
  • 如果重复头的顺序对业务逻辑敏感(例如多个签名令牌需要按序验证),建议在客户端按固定顺序发送,并在测试中验证框架行为是否符合预期,因为不同 ASGI 服务器在合并重复头时未必保持原始顺序。

与 Query / Path 参数相同的能力可以复用

由于 HeaderQueryPathCookie 共享 Param 基类,凡是你在查询参数、路径参数中用过的声明能力,Header 参数几乎都能无缝使用,包括但不限于:

  • 默认值与可选性Header(default=None)str | None 表示可选头;
  • 数值/长度校验gtgeltlemin_lengthmax_lengthpattern
  • 文档元数据titledescriptiondeprecated
  • 显式别名:当你想要的名字无法在 Header 自动转换下得到时,可以直接传 alias(一旦提供显式 alias,FastAPI 会优先使用它,不再执行下划线转换);
  • 在 OpenAPI / Swagger UI 中自动呈现:声明过的 header 会出现在接口文档的请求参数列表中,方便前端联调。

小结

  • 声明 Header 参数要显式使用 Header,否则参数会被当作 Query 处理;
  • 写法上可选用 Annotated[str | None, Header()](推荐)或 str | None = Header(default=None)
  • 默认情况下 FastAPI 会把参数名中的下划线 _ 自动转换为 HTTP 请求头的连字符 -,因此写 user_agent 即对应 User-Agent,且无需担心大小写;
  • 确需保留下划线时,设置 Header(convert_underscores=False),但要警惕部分代理/服务器对下划线请求头的限制;
  • 需要接收出现多次的请求头时,把参数类型声明为 list[...],FastAPI 会以 Python 列表形式返回全部值。

无论你的接口要读取 User-Agent 做客户端识别、校验 X-Token 做鉴权,还是解析各类自定义扩展头,掌握了 Header 参数与自动转换规则之后,都可以用最贴近 Python 习惯的代码把它们稳妥地接入 FastAPI 路径操作函数中。要深入了解 Header 之外的其他参数类型,可继续阅读 Query 参数教程Path 参数教程(同一教程系列的相邻章节),它们共享本指南介绍的这套声明体系与校验模型。

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

项目优选

收起
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