首页
/ FastAPI 设置响应 Cookie 的两种方式:`Response` 参数注入与直接返回 `Response` 的完整实战指南

FastAPI 设置响应 Cookie 的两种方式:`Response` 参数注入与直接返回 `Response` 的完整实战指南

2026-09-08 22:17:32作者:劳婵绚Shirley

导读:在 FastAPI 中为 HTTP 响应添加 Set-Cookie,官方文档 docs/pt/docs/advanced/response-cookies.md(各语言版本同源)给出了两条并行的官方路径——在路径操作函数中声明 Response 类型的参数,由框架将参数中的 Cookie/Header/状态码"回填"进最终响应;或者直接构造并返回一个携带 Cookie 的 Response 对象。读完本文,你将掌握两种方式各自的代码写法、适用边界、与 response_model 的协作关系,以及背后的依赖注入与响应合并实现原理,并配合本仓库的源码与测试用例进行验证。

在 FastAPI 应用中,"设置响应 Cookie"是登录态下发、会话跟踪、埋点标识等场景的基础操作。与多数 Web 框架需要访问全局响应对象不同,FastAPI 的 Cookie 写入依赖其独有的依赖注入体系与可组合的响应对象设计,且官方文档刻意将用法区分为两种风格。下文先讲与"返回值模型"天然兼容的 Response 参数注入法,再讲完全掌控输出的直接返回法,最后结合仓库实现源码剖析两者在内部是如何被处理的。

一、使用 Response 参数:在"临时响应"上设置 Cookie

官方文档首先推荐的方式是:在路径操作函数中声明一个类型为 Response 的参数,然后在函数体内对这个由框架注入的响应对象调用 set_cookie()

参考 docs_src/response_cookies/tutorial002_py310.py 中的官方示例:

from fastapi import FastAPI, Response

app = FastAPI()


@app.post("/cookie-and-object/")
def create_cookie(response: Response):
    response.set_cookie(key="fakesession", value="fake-cookie-session-value")
    return {"message": "Come to the dark side, we have cookies"}
# 启动服务后请求验证
curl -i -X POST http://127.0.0.1:8000/cookie-and-object/

关键要点如下:

  • 返回体与响应元数据解耦:函数依然像平常一样 return {"message": ...}(也可以返回数据库模型、Pydantic 模型等任意对象),无需在返回值中拼接 Cookie 信息。对 response 参数的 set_cookie() 调用与返回值互不干扰。
  • response_model 依旧生效:如果你同时声明了 response_model,它仍会被用于过滤与转换最终返回的对象。也就是说,类型过滤、字段裁剪、序列化照常进行,Cookie 只是被"附加"到最终响应之上。
  • 内部机制:FastAPI 会把这个注入的 Response 当作临时响应容器,提取其中的 Cookie(同样也包括自定义 Header 与状态码),随后将其合并进"包含你返回的值、并经过 response_model 过滤后的最终响应"。因此两者并不会互相覆盖或丢失。
  • 可扩展性:同样的技巧也能用在依赖中——在依赖函数里声明 Response 参数并设置 Cookie(或 Header),那么所有依赖该子依赖的路由都会自动带上这些 Cookie,非常适合做统一的会话/埋点逻辑。

依赖注入场景:在依赖中统一下发 Cookie

from fastapi import Depends, FastAPI, Response

app = FastAPI()


def set_session_cookie(response: Response):
    response.set_cookie(key="session", value="s3cr3t", httponly=True)


@app.get("/items/")
def read_items(_: None = Depends(set_session_cookie)):
    return [{"item": "Portal Gun"}, {"item": "Plumbus"}]

依赖中注入 Response 的原理与路径操作函数中完全一致,均由 FastAPI 的依赖求解器统一处理,因此可以天然组合出"鉴权依赖负责下发会话 Cookie"这类结构。

二、直接返回 Response:在代码中创建携带 Cookie 的响应

另一种官方给出的方式是绕开依赖注入,在代码里显式构造一个响应对象、设置 Cookie 后直接返回。参考 docs_src/response_cookies/tutorial001_py310.py 的官方示例:

from fastapi import FastAPI
from fastapi.responses import JSONResponse

app = FastAPI()


@app.post("/cookie/")
def create_cookie():
    content = {"message": "Come to the dark side, we have cookies"}
    response = JSONResponse(content=content)
    response.set_cookie(key="fakesession", value="fake-cookie-session-value")
    return response
curl -i -X POST http://127.0.0.1:8000/cookie/
# 响应头中应出现: Set-Cookie: fakesession=fake-cookie-session-value

这套流程的通用写法是:

  1. 先按照直接返回 Response 一节的方法创建任意响应对象(JSONResponseHTMLResponseRedirectResponse 或自定义 Response 子类均可);
  2. 调用该对象的 set_cookie() 写入 Cookie;
  3. 将该对象直接作为路径操作函数的返回值返回。

直接返回时的两点重要提醒

官方文档专门给出提示,直接返回响应对象与使用 Response 参数存在本质差异,务必注意:

  • 不再经过 response_model 过滤:当你直接返回 Response 时,FastAPI 会原样直接返回它,跳过正常的响应序列化与 response_model 数据过滤链路。因此必须自己保证数据形态正确——例如返回 JSONResponse 时,其 content 必须是可被 JSON 序列化的数据;同时不要携带任何本应由 response_model 剔除的敏感或多余字段。
  • Cookie 设置在响应对象上:因为响应已经由你完整掌控,设置 Cookie 需要直接在该对象上调用 set_cookie(),而不是依赖参数注入。

三、set_cookie() 可配置的参数选项

两种方式最终都汇聚到 Response.set_cookie() 方法。下表汇总了该方法的关键参数(以当前仓库所依赖的 Starlette 响应基类实现为准,该对象同样可通过 fastapi.responses 导入):

参数 含义 典型取值
key Cookie 名称 任意字符串,如 "session"
value Cookie 值(默认空串) 字符串;复杂值建议先编码
max_age 过期时间(秒),或 datetime.timedelta 1800 表示 30 分钟会话
expires 过期时间点(datetimeint 时间戳) max_age 二选一使用
path Cookie 生效路径(默认 / "/app"
domain 生效域名 "example.com"
secure 仅 HTTPS 传输 True
httponly 禁止 JavaScript 读取(防 XSS 窃取) True
samesite 跨站策略:"lax" / "strict" / "none" "lax"

一个带完整属性的调用示例:

response.set_cookie(
    key="fakesession",
    value="fake-cookie-session-value",
    max_age=1800,
    path="/",
    secure=True,
    httponly=True,
    samesite="lax",
)

官方文档指出,更多参数与选项的完整列表以 Starlette 的 set-cookie 说明为准;其底层行为等同于标准 HTTP 的 Set-Cookie 响应头。

四、源码级剖析:Cookie 是如何"回到"最终响应的

在仓库中,Response 参数注入的本质是 FastAPI 依赖求解器的一项约定。位于 fastapi/routing.py 的路由处理逻辑会针对这一约定做专门处理,使两类返回风格在底层走不同但各自正确的链路:

4.1 直接返回 Response

fastapi/routing.py 中执行完端点函数(run_endpoint_function)后,会对返回值做类型判断。若 raw_response 本身已是 Response 实例,则直接采纳它作为最终响应,仅在背景任务为空时把依赖中累积的 background_tasks 挂上去——可见 Cookie、状态码、响应体完全由你构造的对象决定,这也解释了为何直接返回时 response_model 不再介入。

4.2 返回普通对象时(Response 参数路径)

若端点返回的是普通数据(dict、模型等),FastAPI 会调用 _build_response_args 收集由依赖求解阶段产生的状态码、Header 与 Cookie 等"响应参数",据此构造出承载序列化结果(serialize_response,必要时走 Pydantic 直出 JSON 字节的快路径)的最终响应对象。其中,从注入的临时 Response 上提取的原始响应头(含 Set-Cookie)会被合并进最终响应。这正是文档所述"临时响应中设置的 Cookie/Header/状态码被放入最终响应"的实现落点。

4.3 导入路径的技术细节

官方文档的技术细节注明:fastapi.responses 中的响应类与 starlette.responses 一致,仅是出于便利而对开发者的再导出。对照 fastapi/responses.py 的源码可见:

from starlette.responses import Response as Response  # noqa
from starlette.responses import JSONResponse as JSONResponse  # noqa
# ... FileResponse / HTMLResponse / PlainTextResponse / RedirectResponse / StreamingResponse 同理

也就是说,多数响应类型直接来自 Starlette,因此 from fastapi.responses import Responsefrom starlette.responses import Response 等价;而由于 Response 常被用来设置 Header 与 Cookie,FastAPI 特意在 fastapi.Response 顶层位置也提供了它。代码中可以使用任意一种导入写法,效果相同。

五、用仓库测试用例验证两种写法

仓库为两个官方示例分别配备了端到端测试,可直接作为行为契约:

  • tests/test_tutorial/test_response_cookies/test_tutorial001.py:对应 tutorial001_py310.py(直接返回 JSONResponse)。测试断言 POST /cookie/ 返回 200,JSON 体精确等于 {"message": "Come to the dark side, we have cookies"},并且 response.cookies["fakesession"] 等于 "fake-cookie-session-value"
  • tests/test_tutorial/test_response_cookies/ 下的 test_tutorial002.py 对应 tutorial002_py310.pyResponse 参数注入写法),同样验证 Set-Cookie 出现在最终响应中。

本地复现这些断言并不需要真实启动服务器,直接使用 FastAPI 自带的 TestClient(其底层基于 Starlette 的测试传输层)即可:

from fastapi.testclient import TestClient

from docs_src.response_cookies.tutorial001_py310 import app

client = TestClient(app)


def test_path_operation():
    response = client.post("/cookie/")
    assert response.status_code == 200, response.text
    assert response.json() == {"message": "Come to the dark side, we have cookies"}
    assert response.cookies["fakesession"] == "fake-cookie-session-value"
# 在仓库根目录执行
python -m pytest tests/test_tutorial/test_response_cookies/ -q

六、两种方式的选型建议

判断维度 Response 参数注入 直接返回 Response
返回值形态 任意对象(dict、模型等),保持 REST 风格 Response 实例本身
response_model 仍然生效,会过滤/转换返回数据 不生效,完全由自己保证数据正确
典型场景 常规接口额外附加会话 Cookie;在依赖中统一下发 Cookie/Header 需要完全控制响应内容、状态码、媒体类型与 Header(含跳转、文件、流式等)
组合能力 可同时声明 response_model、自定义状态码、额外 Header 借助 RedirectResponseFileResponseStreamingResponse 等子类获得丰富能力

若只是"返回 JSON 的同时顺手种一个 Cookie",优先使用 Response 参数注入,因为它让数据过滤、类型校验与 Cookie 设置各司其职;若你本就要构造 RedirectResponse、文件下载或流式响应等特殊响应,则直接在对象上调用 set_cookie() 再返回,是更自然的做法。两者的最终效果都等价于在 HTTP 响应中输出正确的 Set-Cookie 头,可在浏览器开发者工具或 curl -i 中确认。

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

项目优选

收起
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
898
5.82 K
kernelkernel
openEuler内核是openEuler操作系统的核心,既是系统性能与稳定性的基石,也是连接处理器、设备与服务的桥梁。
C
531
596
ops-nnops-nn
本项目是CANN提供的神经网络类计算算子库,实现网络在NPU上加速计算。
C++
921
1.84 K
jiuwenswarmjiuwenswarm
JiuwenSwarm 是一款基于openJiuwen开发的智能AI Agent,它能够将大语言模型的强大能力,通过你日常使用的各类通讯应用,直接延伸至你的指尖。
Python
3.8 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
391