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

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

2026-09-08 19:56:13作者:翟江哲Frasier

本篇文章基于 FastAPI 官方教程日文版《ヘッダーのパラメータ》(即 docs/ja/docs/tutorial/header-params.md)展开,系统讲解在 FastAPI 中如何像声明查询参数、路径参数和 Cookie 一样声明 HTTP 请求头参数,并深入解析其底层实现:包括 Header 的导入与声明、变量名下划线到连字符的自动转换机制、convert_underscores 开关的使用场景与风险,以及如何用类型注解接收同一名称出现多次的重复请求头。读完本文,你将能独立实现诸如读取 User-Agent、自定义 X-Token 等真实请求头需求,并理解其背后的 FastAPI 源码行为。

为什么需要专门的 Header

HTTP 请求中经常需要读取请求头(header),例如客户端类型 User-Agent、认证令牌 X-Token、内容协商相关的 Accept-Language 等。FastAPI 提供了一种与 QueryPathCookie 完全对称 的声明方式:请求头参数同样通过在函数签名中做类型标注来声明,并自动获得类型校验、OpenAPI 文档生成、交互式文档展示等能力。

需要特别强调的是:声明请求头必须使用 Header。教程在"note"提示中明确指出,如果不用 Header 而仅做普通类型标注,FastAPI 会把该参数解释为查询参数(query parameter),而不是请求头。这一点从源码也可以得到印证:在 fastapi/dependencies/utils.py 中,当一个标量参数没有显式指定 FieldInfo(如 QueryPath 等)时,会被默认归类到 params.Query,从而进入查询参数通道。

导入 Header

fastapi 中导入 Header 与导入其他参数类型没有区别,参考示例源码 docs_src/header_params/tutorial001_an_py310.py

from typing import Annotated

from fastapi import FastAPI, Header

app = FastAPI()

声明请求头参数

方式一:使用 Annotated(推荐,本仓库示例采用的写法)

@app.get("/items/")
async def read_items(user_agent: Annotated[str | None, Header()] = None):
    return {"User-Agent": user_agent}
  • 类型标注为 str | None,默认值 None,表示该请求头可选;客户端不发送时 user_agent 即为 None
  • Header() 告诉 FastAPI 这是从 HTTP 请求头中取值;
  • 除了默认值,Header() 内还可以传入与 Query/Path/Cookie 相同的额外校验参数与注解参数,例如 titledescriptionmin_lengthmax_lengthpatterngtgeltleexamples 等,声明方式完全一致。

方式二:使用默认值语法

对于不使用 Annotated 的 Python 版本写法,教程对应的非 Annotated 版本见 docs_src/header_params/tutorial001_py310.py

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

两种写法语义等价。仓库中的单元测试 tests/test_tutorial/test_header_params/test_tutorial001.py 会同时加载 tutorial001_py310tutorial001_an_py310 两个模块分别验证。

技术细节:Header 到底是什么

教程的"技术细节"说明框指出:

  • HeaderPathQueryCookie 的"姊妹类",它们共同继承自同一个公共基类 Param
  • 但请注意:从 fastapi 导入的 QueryPathHeader 等在形式上看起来像类,实际上返回特殊类的函数

这一点可以在源码中得到完整验证:

  • fastapi/param_functions.pydef Header(...) 是一个函数(含 # noqa: N802 说明其刻意使用大写命名),它收集全部关键字参数后最终实例化并返回 params.Header(...)
  • fastapi/params.py 中定义了真正的 class Header(Param),并在类体内通过 in_ = ParamTypes.header 标记该参数取自请求头。

自动转换:下划线 _ 到连字符 -

Header 相比 PathQueryCookie 多出了一项能力:自动转换

HTTP 标准请求头的名字大多用连字符(hyphen,即减号 -)分隔,例如 User-AgentX-Token。但在 Python 里,user-agent 这种写法是非法标识符,无法直接用作函数参数名。

因此,默认情况下 Header 会把你声明的 Python 参数名中的下划线 _ 自动转换为连字符 -,再用转换后的名字去实际请求头中取值,并以此名字生成 OpenAPI 文档。

同时,由于 HTTP 请求头本身不区分大小写,你可以完全按 Python 的 snake_case 风格书写参数名。也就是说,读取 User-Agent 时不必写成 User_Agent 这种别扭形式,直接写:

async def read_items(user_agent: Annotated[str | None, Header()] = None):
    ...

FastAPI 会帮你把 user_agent 匹配到实际的 User-Agent 请求头。

源码层面的转换实现

这一转换在 FastAPI 依赖解析时完成,见 fastapi/dependencies/utils.py

if not field_info.alias and getattr(field_info, "convert_underscores", None):
    alias = param_name.replace("_", "-")
else:
    alias = field_info.alias or param_name
field_info.alias = alias

逻辑要点:

  • 只有当参数名没有被显式 alias 覆盖、且 convert_underscores 开启时,才执行 param_name.replace("_", "-")
  • 转换后的字符串被写回 field_info.alias,后续请求头取值与 OpenAPI 生成都以该 alias 为准。

从生成的 OpenAPI Schema 可以直观看到转换结果。测试 tests/test_tutorial/test_header_params/test_tutorial001.py 中的 test_openapi_schema 断言了 /openapi.json 中参数对象为:

{
    "required": false,
    "schema": {"anyOf": [{"type": "string"}, {"type": "null"}]},
    "name": "user-agent",
    "in": "header"
}

即:Python 参数 user_agent 在文档中呈现为请求头 user-agent(header 请求头名大小写不敏感,文档中用小写展示是惯例)。

用测试验证运行行为

test_tutorial001.py 的请求级测试也验证了实际取值逻辑:

("/items", None, 200, {"User-Agent": "testclient"}),
("/items", {"X-Header": "notvalid"}, 200, {"User-Agent": "testclient"}),
("/items", {"User-Agent": "FastAPI test"}, 200, {"User-Agent": "FastAPI test"}),
  • 不发送任何请求头时,默认 user_agentNone……(在 TestClient 环境下,默认请求会携带 User-Agent: testclient,因此无参请求也能取到该默认值);
  • 发送 User-Agent: FastAPI test 时,user_agent 准确取到字符串 FastAPI test
  • 发送无关请求头 X-Header 不影响取值。

关闭自动转换:convert_underscores=False

绝大多数场景下你应该保持自动转换开启。但假如出于某种原因,你需要请求头中保留下划线(例如某些内部或历史系统的自定义头就叫 X_Strange_Header),可以给 Header 传入 convert_underscores=False

示例见 docs_src/header_params/tutorial002_an_py310.py

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

这样声明后,FastAPI 不会把 strange_header 中的下划线转为连字符,而是直接用原名去请求头中匹配名为 strange_header 的头(由于 HTTP 头大小写不敏感,Strange_Header 等大小写写法也可命中)。

该参数在源码中的默认值是 True。在 fastapi/param_functions.py 的函数签名与 fastapi/params.py 的类构造器中均可看到:

convert_underscores: bool = True,

同时,fastapi/openapi/utils.py 在生成 OpenAPI 时也会读取该标记,用于决定文档中 header 名称应保持下划线形式还是转换为连字符形式,保证"文档与实际请求头名称"一致。

官方警告:使用下划线请求头的风险

教程特别给出了 warning:在把 convert_underscores 设为 False 之前,务必意识到某些 HTTP 代理(proxy)和服务器不允许使用包含下划线的请求头。 也就是说,即使你的应用代码这样声明了,实际部署环境中若中间经过这类代理/服务器,带下划线的头可能在到达应用前就被丢弃或拒绝。因此,是否关闭自动转换需要在真实部署环境中谨慎评估,一般建议优先使用标准的连字符命名。

接收重复的请求头:类型声明为 list

HTTP 规范允许同一个请求头在报文中出现多次,即同一名称携带多个值。例如:

X-Token: foo
X-Token: bar

要接收全部值,只需在类型声明中把参数类型写成 list(并搭配可空标注使该头可选)。示例见 docs_src/header_params/tutorial003_an_py310.py

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

此时 FastAPI 会把重复请求头的所有值作为一个 Python list 传入。对于上面的两条 X-Token,接口返回:

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

测试对重复头的验证

tests/test_tutorial/test_header_params/test_tutorial003.py 使用元组列表的方式模拟重复头并断言结果:

("/items", None, 200, {"X-Token values": None}),
("/items", {"x-token": "foo"}, 200, {"X-Token values": ["foo"]}),
("/items", [("x-token", "foo"), ("x-token", "bar")], 200, {"X-Token values": ["foo", "bar"]}),

可以看到:

  • 未发送该头时返回 None
  • 发送单个 x-token: foo 时返回单元素列表 ["foo"]
  • 发送两条时完整返回 ["foo", "bar"]

同时 test_openapi_schema 断言了该参数在 OpenAPI 中的 schema 类型为数组:

{
    "name": "x-token",
    "in": "header",
    "schema": {
        "title": "X-Token",
        "anyOf": [
            {"type": "array", "items": {"type": "string"}},
            {"type": "null"}
        ]
    }
}

即 Python 类型 list[str] | None 被正确映射为可空字符串数组,Swagger UI(/docs)中会据此展示该参数可多次添加。

运行与验证方式

教程对应的可运行示例全部位于 docs_src/header_params/ 目录:

示例文件 讲解内容
tutorial001_an_py310.py / tutorial001_py310.py 基础请求头声明(读取 User-Agent),Annotated 与默认值两种写法
tutorial002_an_py310.py / tutorial002_py310.py convert_underscores=False 关闭自动转换
tutorial003_an_py310.py / tutorial003_py310.py list 接收重复请求头 X-Token

需要本机验证时,可任选其中一个文件(例如 tutorial001_an_py310.py),用 Uvicorn 启动:

uvicorn docs_src.header_params.tutorial001_an_py310:app --reload

随后访问 http://127.0.0.1:8000/docs 在 Swagger UI 中填写请求头并发送,或直接访问 http://127.0.0.1:8000/items/ 观察 User-Agent 回显。仓库中 _an_py310 后缀表示该版本基于 Python 3.10+ 的 typing.Annotated 语法;若运行环境版本较低,可对照阅读其非 Annotated 版本。

小结

  • 请求头参数使用 Header 声明,其声明模式与 QueryPathCookie 完全相同,并共享同一套默认值、校验与注解参数能力;
  • 请求头必须使用 Header,否则会被当作查询参数处理;
  • 默认情况下,FastAPI 自动把参数名中的下划线 _ 转为连字符 -,且不区分大小写,因此可以直接用 user_agent 匹配 User-Agent
  • 若需要保留带下划线的请求头,设置 Header(convert_underscores=False),但需先确认部署链路上的代理与服务器允许这类头;
  • 同一请求头可能出现多次,把参数类型声明为 list 即可接收其全部值。

Header 的类定义(fastapi/params.py)、参数收集函数(fastapi/param_functions.py)到依赖解析中的 alias 转换(fastapi/dependencies/utils.py)以及 OpenAPI 生成逻辑(fastapi/openapi/utils.py),整个请求头处理链路环环相扣——声明请求头时你不必操心变量名中的下划线,FastAPI 会为你完成全部转换

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

项目优选

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