首页 / FastAPI 入门教程 / Cookie、Header 与额外数据类型

FastAPI 入门教程

Cookie、Header 与额外数据类型

本教程共 50 篇 · 第 18 篇 · 更新于 2026-08-12 · 约 9 分钟阅读

FastAPIFastAPI 入门教程CookieHeader额外数据类型UUID

本节目标:学会用 CookieHeader 读取请求里的 Cookie 与请求头,并了解 FastAPI 对 datetime、UUID、bytes、Decimal 等类型的自动转换与校验。

除了路径参数、查询参数、请求体,HTTP 请求里还有两类常见数据:Cookie请求头(Header)。另外,FastAPI 借助 Pydantic,还能直接处理许多”非基础”的 Python 数据类型。本章把它们一起讲清楚。

读取 Cookie 的方式和读取查询参数几乎一样,只是把 Query 换成 Cookie。你必须显式用 Cookie,否则 FastAPI 会把它当成查询参数。

from fastapi import Cookie, FastAPI

app = FastAPI()


@app.get("/items/")
async def read_items(ads_id: str | None = Cookie(default=None)) -> dict:
    return {"ads_id": ads_id}

这里 ads_id 从客户端请求携带的 Cookie 里读取。没传就是 NoneCookieQueryPath 是”姐妹类”,都支持默认值、校验规则那一套。

Note

在浏览器里,Cookie 由浏览器底层管理,JavaScript 不能随意触碰。所以你在 /docs 里填了 Cookie 点”Execute”,因为文档界面是 JS 发的请求,Cookie 实际发不出去,会看到像没传值一样的报错。这不是代码错,用真实客户端(如前端 fetch、requests)测试就好。

如何用 Response.set_cookie(...) 下发 Cookie,在第 15 章已经讲过,这里不再赘述。

18-2 用 Header 读取请求头

读请求头同理,用 Header

from fastapi import FastAPI, Header

app = FastAPI()


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

访问后,返回的 JSON 里就带有浏览器的 User-Agent 信息。

18-3 下划线自动转连字符

HTTP 请求头的名字用连字符,比如 X-TokenUser-Agent。可 Python 变量名不允许有连字符,所以你写 x_token,FastAPI 会自动把它映射成 X-Token

from fastapi import FastAPI, Header

app = FastAPI()


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

转换规则对照:

Python 变量名对应的 HTTP 头
x_tokenX-Token
user_agentUser-Agent
content_typeContent-Type

HTTP 头本身不区分大小写,所以你用 snake_casex_token)写法完全没问题,不用去大写首字母。

Tip

极少数情况下你想关闭这个自动转换,可以写 Header(default=None, convert_underscores=False)。但注意,有些 HTTP 代理和服务器禁止使用带下划线的头,一般不建议关。

18-4 接收重复的请求头

有的头可能在一个请求里出现多次(比如 Set-Cookie)。用 list 类型声明,FastAPI 会把所有值收集成一个列表返回给你。

from fastapi import FastAPI, Header

app = FastAPI()


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

如果客户端发了:

X-Token: foo
X-Token: bar

响应就是 {"X-Token values": ["foo", "bar"]}

18-5 额外数据类型:datetime

除了 intfloatstrbool 这些基础类型,FastAPI 还支持一大批”额外数据类型”,而且照样享有编辑器支持、自动转换、校验和文档生成。

datetime.datetime 表示一个具体时刻。客户端传字符串(ISO 8601 格式),FastAPI 自动转成 Python 的 datetime 对象。

from datetime import datetime

from fastapi import FastAPI

app = FastAPI()


@app.get("/events/")
async def read_events(started_after: datetime | None = None) -> dict:
    if started_after:
        return {"started_after": started_after.isoformat()}
    return {"started_after": None}

请求 /events/?started_after=2024-09-15T15:53:00+08:00,函数里拿到的 started_after 就是真正的 datetime 对象,你可以直接调用 .isoformat() 等方法做日期运算。同样的规则也适用于 datetime.date(只含日期)和 datetime.time(只含时刻)。

18-6 额外数据类型:UUID

UUID 是通用的唯一标识符,很多数据库用它当主键。客户端传字符串形式的 UUID,FastAPI 自动转成 Python 的 uuid.UUID 对象,并会校验格式是否合法。

import uuid

from fastapi import FastAPI

app = FastAPI()


@app.get("/items/{item_id}")
async def read_item(item_id: uuid.UUID) -> dict:
    return {"item_id": item_id, "item_id_type": type(item_id).__name__}

访问 /items/9c2c1b9e-0b3a-4f1e-8d2a-1a2b3c4d5e6fitem_id 已是 UUID 实例,且格式错误会被直接拦截。

18-7 额外数据类型:bytes 与 Decimal

bytes 表示二进制数据。在请求和响应里它表现为字符串,但 FastAPI 会按二进制处理,生成的 JSON Schema 里标记为 binary 格式。

Decimal 是高精度小数(避免浮点误差),处理方式和 float 类似,适合金额这类对精度敏感的数据。

from decimal import Decimal

from fastapi import FastAPI

app = FastAPI()


@app.get("/calc/")
async def calc(amount: Decimal | None = None) -> dict:
    if amount is None:
        return {"amount": None}
    return {"amount": str(amount), "doubled": str(amount * 2)}

请求 /calc/?amount=10.05amountDecimal 类型,做 amount * 2 精确计算不会丢精度。

18-8 综合示例

把几种额外类型放在一起,体会一下”声明即校验、调用即得对象”的爽感:

from datetime import datetime
from decimal import Decimal
from uuid import UUID

from fastapi import FastAPI

app = FastAPI()


@app.put("/items/{item_id}")
async def update_item(
    item_id: UUID,
    start_time: datetime | None = None,
    price: Decimal | None = None,
) -> dict:
    result = {
        "item_id": str(item_id),
        "start_time": start_time.isoformat() if start_time else None,
        "price": str(price) if price else None,
    }
    return result

item_id 会被校验成合法 UUID,start_time 转成 datetimeprice 转成 Decimal。凡是不符合格式的请求,FastAPI 自动返回 422 校验错误,你一行校验代码都不用写。

18-9 综合示例:读取请求头、Cookie 并处理额外类型

把 Cookie、Header、UUID、datetime 放到一个接口里,看 FastAPI 如何一站式解析:

from datetime import datetime
from uuid import UUID

from fastapi import Cookie, FastAPI, Header

app = FastAPI()


@app.post("/upload/{task_id}")
async def upload(
    task_id: UUID,
    token: str | None = Header(default=None),
    session: str | None = Cookie(default=None),
    happened_at: datetime | None = None,
) -> dict:
    return {
        "task_id": str(task_id),
        "token": token,
        "session": session,
        "happened_at": happened_at.isoformat() if happened_at else None,
    }

请求时,URL 里的 task_id 被校验成 UUIDtokenToken 请求头读取(变量名 token 自动对应 Token 头),session 从 Cookie 读取,happened_at 从查询参数解析成 datetime。函数体内拿到的全是可以直接用的 Python 对象,不用自己写任何转换或校验代码。

Tip

额外数据类型还有 datetime.timedelta(时长,在 Pydantic v2 中以 ISO 8601 时长字符串传输,如 P1DT1H1M1S)、frozenset(去重集合)等。完整清单可查 Pydantic 官方数据类型文档。记住一个原则:能用标准 Python 类型声明,就别自己手写字符串解析。

需要强调:这些额外类型的”自动转换”只发生在 FastAPI 接收请求参数(路径、查询、Header、Cookie、请求体字段)的时候。函数内部你拿到的已经是真正的 Python 对象,可以直接调用对象的方法,比如对 datetime 做加减、对 Decimal 做精确运算、对 UUID.hex 等。这也意味着,如果你的客户端传了一个格式不对的 UUID 或日期字符串,FastAPI 会在进入函数前就返回 422 校验错误,你的业务代码根本不会被调用,从而避免了”脏数据进业务逻辑”的麻烦。

18-10 小结

Cookie、Header 和额外数据类型,让接口能承载更丰富的信息:

  • Cookie(...) 读取请求里的 Cookie,用 Header(...) 读取请求头。
  • Header 自动把变量名下划线转成头的连字符,大小写不敏感。
  • list[str] 接收重复出现的请求头。
  • 额外数据类型(如 datetimeUUIDbytesDecimal)享受和基础类型一样的自动转换、校验、文档生成。
  • 这些类型在请求里以字符串呈现,进入函数后已是对应 Python 对象,直接拿来用即可。