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

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

2026-09-06 19:24:36作者:彭桢灵Jeremy

在 FastAPI 中设置响应 Cookie 主要有两条官方推荐的实现路径:其一是在 path operation function(路径操作函数)或依赖中声明一个 Response 类型参数,把 Cookie「暂存」在由框架创建的临时响应对象上,随后照常返回任意业务对象;其二是直接构造并返回一个带 Cookie 的 Response(如 JSONResponse)。本文以仓库中的官方教程文档 docs/es/docs/advanced/response-cookies.md 为主体骨架,结合配套源码示例与测试用例,系统讲解这两种方案的写法、运行效果、与 response_model 的协作关系及底层实现细节。读完你将能够在自己的 FastAPI 应用中准确、安全地给客户端种下会话 Cookie。

两种方案与配套示例源码一览

仓库在 docs_src/response_cookies/ 目录下提供了与本文档一一对应的两个可运行示例:

方案 示例源码 路由路径
使用 Response 参数(临时响应对象) tutorial002_py310.py POST /cookie-and-object/
直接返回 Response tutorial001_py310.py POST /cookie/

两个文件都以 py310 命名,示例代码使用 def(同步)写法,语义上与 Python 3.10+ 环境下可直接运行;对应的自动化测试位于 tests/test_tutorial/test_response_cookies/。下面逐一展开。

方案一:声明 Response 参数设置 Cookie

path operation function 中声明一个 Response 类型的形参,随后调用该临时响应对象的 set_cookie() 方法即可:

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"}

对应仓库文件:tutorial002_py310.py

这里的执行逻辑非常符合直觉:

  1. FastAPI 的依赖注入系统会为 response 参数准备好一个临时Response 对象;
  2. 你调用 response.set_cookie(key=..., value=...),把 Cookie 写入这个临时对象;
  3. 函数最后仍像平时一样返回任意对象(dict、数据库模型等),而无需手动组装 HTTP 响应;
  4. FastAPI 会从该临时 Response 中提取 Cookie(同样还有 Headers 与状态码),并入最终响应返回给客户端。

与 response_model 的协作

如果同时声明了 response_model,它仍然会对你的返回值执行过滤与类型转换。也就是说,返回的对象会先经过 response_model 的校验/序列化处理,而通过 Response 参数设置的 Cookie 独立于数据模型之外、原样保留在最终 HTTP 响应头中。这种「业务数据交给模型、传输控制交给 Response 参数」的职责划分,正是该方案相比直接返回 Response 的最大优势。

在依赖中设置 Cookie

同样的技巧也适用于依赖(Dependencies):你可以在依赖函数里声明 Response 参数并调用 set_cookie()(也可设置 Headers)。这样,凡是使用该依赖的路径操作都会自动附带统一的 Cookie——非常适用于集中式的会话初始化、埋点标识下发等横切场景。

方案二:直接返回带 Cookie 的 Response

另一种做法是放弃框架的返回序列化管线,直接在代码中创建 Response 实例、设置 Cookie 并返回它:

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

对应仓库文件:tutorial001_py310.py

该方案的核心步骤是:

  1. 直接返回 Response 教程中的方式构造一个响应对象(此处使用 JSONResponse 并传入 content);
  2. 调用 response.set_cookie(...) 设置 Cookie;
  3. 直接 return response

⚠️ 直接返回时的注意事项

官方文档特别提醒:如果直接返回 Response,FastAPI 会原样返回它,不再走 response_model 的过滤与转换流程。因此你必须自己确保:

  • 返回的数据类型正确。例如返回 JSONResponse 时,content 必须是 JSON 可序列化的;
  • 数据已经按预期准备好,不要遗漏任何「本应由 response_model 帮你剔除」的敏感字段,因为此时模型过滤不会再起作用。

也就是说,方案二把数据的「生产与整形」责任完全交给了开发者,换取的是对最终响应头、状态码、Cookie 的全量直接控制。

两种方案的差异与选型建议

对比维度 方案一(Response 参数) 方案二(直接返回 Response
返回值形态 可返回任意对象(dict、模型、ORM 对象等) 必须返回 Response 实例本身
response_model 仍生效,会自动过滤/转换返回数据 不生效,需手动保证数据形态正确
Cookie/Headers/状态码 从临时响应对象提取后合并进最终响应 直接跟随该响应对象
适用场景 常规业务接口附带会话 Cookie 需要完全自定义响应的场景

从源码看:fastapi.Response 与 starlette.responses 的关系

fastapi/responses.py 中可以看到,ResponseJSONResponseHTMLResponseRedirectResponseStreamingResponseFileResponse 等几乎全部响应类,都是直接从 starlette.responses 重新导出(re-export)的:

from starlette.responses import FileResponse as FileResponse
from starlette.responses import JSONResponse as JSONResponse
from starlette.responses import Response as Response
...

也就是说:from fastapi.responses import Responsefrom starlette.responses import Response 指向的是同一个类,绝大多数可用的响应实现都源自 Starlette。FastAPI 之所以统一在其 fastapi.responses(以及 fastapi.Response)命名空间中再暴露一份,纯粹是出于开发者使用上的便利,避免你记忆两套导入来源。由于 Response 对象经常被用来设置 Headers 与 Cookies,FastAPI 因而特别提供了顶层可用的 fastapi.Response

底层响应装配线索

fastapi/routing.py 的源码结构看,每个路径操作在内部都会被包装为一个最终返回 Response 对象的 app(request) 流程:代码先以 response: Response | None = None 初始化响应占位,再进入依赖解析与业务函数调用阶段——这也解释了为何注入的 Response 参数能代表「最终响应本身」:你在临时对象上设置的 Cookie、Headers 与状态码,最终都会被收集并装配到真正发回客户端的响应中。

一次可验证的完整运行

仓库在 tests/test_tutorial/test_response_cookies/ 中为两个示例各准备了一个集成测试,可以直接运行验证:

pytest tests/test_tutorial/test_response_cookies/

例如 test_tutorial002.py 的核心断言为:

from fastapi.testclient import TestClient
from docs_src.response_cookies.tutorial002_py310 import app

client = TestClient(app)

def test_path_operation():
    response = client.post("/cookie-and-object/")
    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"

它同时验证了两件事:接口正常返回 JSON 业务内容,且响应头中确实携带了名为 fakesession、值为 fake-cookie-session-value 的 Cookie。test_tutorial001.py 对方案二(直接返回 JSONResponse)给出了同样的断言,证明两种写法在 HTTP 层表现一致。

若想手动体验,也可将上述示例文件中的 app 交给本地开发服务器启动(例如以 uvicorn docs_src.response_cookies.tutorial002_py310:app --reload 的方式),再用浏览器开发者工具或 curl -v 观察响应中的 Set-Cookie 响应头。注意示例以 py310 命名,建议在 Python 3.10 及以上环境中运行。

更多 Cookie 属性:不止 key 与 value

示例代码只演示了最常用的 keyvalue 两个参数,实际上 Response.set_cookie() 还支持 Cookie 的各类标准属性,可覆盖绝大多数真实业务需求:

  • max_age:Cookie 的最大存活秒数;
  • expires:过期时间(具体日期/时间);
  • path:Cookie 生效的路径范围;
  • domain:Cookie 生效的域名;
  • secure:是否仅在 HTTPS 连接下传输;
  • httponly:是否禁止 JavaScript 读取(抵御 XSS 的关键设置);
  • samesite:跨站请求时是否携带 Cookie(如 lax / strict / none)。

结合 FastAPI/Starlette 官方文档中关于 set_cookie 的参数说明(原文末尾亦提示读者可进一步查阅 Starlette 的响应文档)即可按需选用。在设置会话类 Cookie 时,建议至少考虑 httponlysecuresamesite 的组合,以降低 XSS、CSRF 等 Web 安全风险——这些属性属于标准的 HTTP Cookie 行为,与具体框架无关,但 FastAPI 的 Response.set_cookie() 都提供了直接的透传支持。

小结

回到本仓库的两份教程源码:想要「返回业务数据 + 顺手种下 Cookie」的常规接口,优先采用 tutorial002_py310.pyResponse 参数方案,它保留了 response_model 的全部能力;当你需要完全掌控返回内容、或返回的本身就是某类 Response(重定向、流式、文件等)时,则参考 tutorial001_py310.py 直接构造响应并调用 set_cookie()。前者省心,后者彻底,配合 tests/test_tutorial/test_response_cookies/ 下的集成测试,你可以随时回归验证任意一种写法的正确性。

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