You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

FastAPI结合Pydantic定义kebab-case请求头时,文档与实际行为不一致的解决方案咨询

FastAPI结合Pydantic定义kebab-case请求头时,文档与实际行为不一致的解决方案咨询

我在FastAPI项目里用Pydantic定义通用请求头的时候,遇到了kebab-case字段的问题——请求里的kebab-case头没办法自动转换成对应的snake_case字段,而且生成的Swagger文档也和实际行为不一致。到底该怎么正确定义这个Pydantic头类,才能让文档和实际行为匹配呢?

下面是我整理的最小复现示例:

### main.py

from typing import Annotated
from fastapi import FastAPI, Header
from pydantic import BaseModel, Field

app = FastAPI()


class CommonHeaders(BaseModel):
    simpleheader: str
    a_kebab_header: str | None = Field(
        default=None,
        title="a-kebab-header",
        alias="a-kebab-header",
        description="This is a header that should be specified as `a-kebab-header`",
    )


@app.get("/")
def root_endpoint(
    headers: Annotated[CommonHeaders, Header()],
):
    result = {"headers received": headers}
    return result

运行项目后,打开Swagger文档,看起来是正常的:

Swagger文档里正确显示了kebab-case的请求头字段。

用“Try it out”生成的请求也是符合预期的:

curl -X 'GET' \
  'http://localhost:8000/' \
  -H 'accept: application/json' \
  -H 'simpleheader: foo' \
  -H 'a-kebab-header: bar'

但返回结果里明显能看到kebab-case的头没被正确接收:

{
  "headers received": {
    "simpleheader": "foo",
    "a-kebab-header": null
  }
}

就算把请求里的头改成snake_case的a_kebab_header,也不管用。

后来我修改了头的定义,去掉了title和alias,结果文档和行为还是不一致:

class CommonHeaders(BaseModel):
    simpleheader: str
    a_kebab_header: str | None = Field(
        default=None,
        description="This is a header that should be specified as `a-kebab-header`",
    )

这时候Swagger文档里显示的是snake_case的字段:

Swagger文档里错误地显示了snake_case的请求头字段。

“Try it out”生成的请求也是snake_case的:

curl -X 'GET' \
  'http://localhost:8000/' \
  -H 'accept: application/json' \
  -H 'simpleheader: foo' \
  -H 'a_kebab_header: bar'

但奇怪的是,这个请求也不生效,返回结果里a_kebab_header还是null:

{
  "headers received": {
    "simpleheader": "foo",
    "a_kebab_header": null
  }
}

不过最后我手动把请求里的头改成kebab-case的a-kebab-header,居然成功了:

curl -X 'GET' \
  'http://localhost:8000/' \
  -H 'accept: application/json' \
  -H 'simpleheader: foo' \
  -H 'a-kebab-header: bar'

返回结果里终于拿到了正确的值:

{"headers received":{"simpleheader":"foo","a_kebab_header":"bar"}}

现在我就想知道,到底该怎么正确定义这个Pydantic头类,才能让Swagger文档和实际行为完全匹配? 文档和行为不一致的话,我肯定要被吐槽的。


最后补充一下:我试过不用Pydantic的写法,这种方式下文档和行为都正常(都是kebab-case),但这样就没法定义通用的头结构,每个接口都要重复写一遍,太麻烦了:

"""Alternative version without Pydantic."""
from typing import Annotated
from fastapi import FastAPI, Header

app = FastAPI()


@app.get("/")
def root_endpoint(
    simpleheader: Annotated[str, Header()],
    a_kebab_header: Annotated[
        str | None,
        Header(
            title="a-kebab-header",
            description="This is a header that should be specified as `a-kebab-header`",
        ),
    ] = None,
):
    result = {
        "headers received": {
            "simpleheader": simpleheader,
            "a_kebab_header": a_kebab_header,
        }
    }
    return result

备注:内容来源于stack exchange,提问作者sql_knievel

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.04.14 09:23:01