FastAPI 请求头与 Cookie:Web 世界的“身份证”与“通行证”

你每天上网的时候,有没有好奇过一个问题:

为什么你登录淘宝之后,不管点进"购物车"、"订单详情"还是"个人中心",网站都知道你是谁?

答案并不是你每次点击都把用户名和密码重新发一遍(那样太危险了),而是你的浏览器在每一次请求的背后,悄悄携带了两样东西:请求头(Headers) 和 Cookie。

就像你进小区要刷门禁卡,进公司要刷工牌一样,请求头和 Cookie 就是 Web 世界里辨别你身份的"电子证件"。它们虽然看不见摸不着,但每一次的页面跳转、每一次的 API 调用,都在默默地发挥着作用。

本文将站在普通 Web 用户的视角,深入浅出地讲清楚请求头和 Cookie 到底是什么、有什么区别,以及 FastAPI 如何轻松读取它们,让你的后端服务具备识别用户、控制访问的能力。

一、什么是请求头?(快递包裹的面单)

想象一下,你收到一个快递。

快递盒里装着你买的手机(这是请求体 Body),快递面单上写着你的地址(这是路径参数),面单角落还有备注"轻拿轻放"(这是查询参数)。

但除了这些,快递盒上还有很多你看不到、但对于快递公司至关重要的信息:

寄件人信息(谁发的?)

快递单号(追踪用)

承运方式(空运还是陆运?)

包裹重量(计费依据)

面单版本号(系统识别用)

这些信息,就是 HTTP 请求中的 请求头(Headers)。

请求头是 HTTP 请求的"元数据(Metadata)",即"描述数据的数据"。它不承载业务的核心内容(那是 Body 的活),而是告诉服务器:"我是谁"、"我从哪里来"、"我能接受什么"、"我的连接状态如何"。

在浏览器的开发者工具中(F12 → Network),你可以看到每一个请求都有密密麻麻的

Headers:

复制代码
GET /api/profile HTTP/1.1
Host: example.com
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36
Accept: application/json
Accept-Language: zh-CN,zh;q=0.9
Authorization: Bearer eyJhbGciOiJIUzI1NiIs...
Cookie: session_id=abc123; theme=dark

这些键值对,就是请求头。

二、什么是 Cookie?(商场的会员卡)

Cookie 本质上只是请求头里的一行特殊字段(Cookie: key=value),但它的地位太重要了,值得单独拎出来讲。

想象你去一家大型商场。

如果你每次买东西都要出示身份证(输入用户名密码),太麻烦。

于是商场给你办了一张会员卡(Cookie)。

卡上写着你的会员编号(用户 ID),商场系统通过这张卡识别你是老顾客。

每次你结账时,收银员扫一下卡(浏览器自动携带 Cookie),就知道你是谁、有没有折扣、积分多少。

但会员卡有有效期(过期时间),过期了需要重新激活(重新登录)。

Cookie 的本质,就是服务器颁发给浏览器的一小段文本信息(通常不超过 4KB),浏览器将其保存在本地,并在之后的每一次请求中自动携带回服务器。它主要用于保持会话状态(Session),让无状态的 HTTP 协议"记住"你是谁。

三、请求头 vs Cookie:一张表看懂区别

四、FastAPI 如何读取请求头?

在 FastAPI 中,读取请求头就像读取普通的函数参数一样简单。

  1. 基础用法:使用 Header

    from fastapi import FastAPI, Header

    app = FastAPI()

    @app.get("/user-agent/")
    async def get_user_agent(user_agent: str = Header(None)):
    return {"user_agent": user_agent}

请求:GET /user-agent/,浏览器会自动携带 User-Agent 头。后端直接拿到字符串,比如 "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36"。

注意:Header 默认会把参数名转为小写加下划线的形式(user_agent → User-Agent),非常贴心。

  1. 读取自定义请求头

前端或客户端可以发送自定义请求头(通常以 X- 开头):

复制代码
@app.get("/custom-header/")
async def custom_header(
    x_request_id: str = Header(None, description="自定义请求追踪ID"),
    x_api_version: str = Header("v1")
):
    return {"request_id": x_request_id, "api_version": x_api_version}

前端请求时带上 X-Request-ID: req-2026-001,后端就能拿到这个值用于日志追踪。

  1. 使用 Depends 封装 Header 解析

如果多个接口都需要解析某个请求头(比如 Authorization),可以封装成依赖项复用:

复制代码
from fastapi import Depends, HTTPException

async def get_token(authorization: str = Header(...)):
    if not authorization.startswith("Bearer "):
        raise HTTPException(401, "Invalid token format")
    return authorization.split(" ")[1]

@app.get("/secure-data/")
async def secure_data(token: str = Depends(get_token)):
    return {"token": token, "data": "这是敏感数据"}

五、FastAPI 如何读取 Cookie?

  1. 基础用法:使用 Cookie

FastAPI 提供了 Cookie 函数,用于从请求中提取 Cookie 值:

复制代码
from fastapi import FastAPI, Cookie

app = FastAPI()

@app.get("/profile/")
async def get_profile(session_id: str = Cookie(None)):
    if not session_id:
        return {"error": "未登录"}
    return {"message": f"欢迎回来,你的 session 是 {session_id}"}

浏览器访问 /profile/ 时,会自动携带该域名下的所有 Cookie。Cookie("session_id") 就是从 Cookie: session_id=abc123 中提取 abc123。

  1. 设置 Cookie(服务器响应)

除了读 Cookie,服务器还需要给客户端"发"Cookie。这需要使用 Response 对象:

复制代码
from fastapi import FastAPI, Response

app = FastAPI()

@app.post("/login/")
async def login(response: Response, username: str):
    # 假设验证成功,给浏览器发一个 Cookie
    response.set_cookie(
        key="session_id",
        value="abc123xyz",
        max_age=3600,          # 1小时后过期
        httponly=True,         # 禁止 JavaScript 读取(防 XSS)
        secure=True,           # 仅 HTTPS 传输
        samesite="lax"         # 防 CSRF 攻击
    )
    return {"message": f"{username} 登录成功"}

浏览器收到响应后,会把 session_id=abc123xyz 存到本地。下次再访问同域名下的任何页面,浏览器会自动在请求头里带上 Cookie: session_id=abc123xyz,服务器就知道你是谁了。

六、请求头的五大核心作用(站在用户视角)

  1. 身份认证(你是谁?)

最常见的用途。用户登录后,服务器返回一个 Token(JWT),前端在后续请求中通过 Authorization: Bearer <token> 头发送给服务器。这就是现代 Web 中最主流的无状态认证方式。

用户感知:你登录过一次之后,接下来几天打开 App 都不用重新输密码。

  1. 内容协商(你想要什么格式?)

浏览器通过 Accept 头告诉服务器它能接受什么格式的数据。

Accept: application/json → 请返回 JSON

Accept: text/html → 请返回 HTML

Accept-Language: zh-CN → 请返回中文内容

这就是为什么同一个 API 地址,浏览器访问返回 HTML 页面,移动端访问返回 JSON 数据。

用户感知:你的浏览器自动请求中文页面,而你在国外时自动显示英文,无需手动切换。

  1. 缓存控制(快不快?)

Cache-Control 头告诉服务器和浏览器如何缓存资源,直接影响你的网页加载速度。

用户感知:刷新微博首页时,LOGO 图片几乎是瞬间加载的,因为它被浏览器缓存了。

  1. 安全防护(安不安全?)

Referer:告诉服务器你是从哪个页面跳转过来的,用于防盗链。

User-Agent:告诉服务器你用的什么浏览器,用于适配不同的渲染策略。

Origin:用于 CORS(跨域资源共享),控制哪些网站能调用你的 API。

用户感知:你在 A 网站点击链接跳转到 B 网站,B 网站知道你是从 A 来的,可能给你展示不同的欢迎语。

  1. 追踪与调试(出问题了找谁?)

企业级应用中,请求头常用于链路追踪。每个请求携带一个唯一的 X-Request-ID,贯穿整个微服务调用链。

用户感知:当你在 App 上报 Bug 时,客服让你提供"请求编号",就是这个 ID 帮助你快速定位问题。

七、Cookie 的三大核心作用(站在用户视角)

  1. 会话管理(保持登录态)

这是 Cookie 最经典的应用。用户登录后,服务器下发一个包含用户 ID 的加密 Cookie,浏览器保存。后续每次请求都带着它,服务器就知道你是谁,无需重复登录。

用户感知:你登录淘宝后,关掉浏览器再打开,发现还是登录状态(只要没点"退出登录")。

  1. 用户偏好追踪

网站通过 Cookie 记住你的个性化设置。

用户感知:你把网站主题改成"深色模式",下次打开还是深色模式;你在购物车加的商品,隔天还在。

  1. 流量分析与个性化推荐

第三方追踪 Cookie(如 Google Analytics)记录你的浏览行为,用于分析流量和推送广告。

用户感知:你搜过"旅行箱"后,接下来几天到处都能看到旅行箱广告------这就是追踪 Cookie 的"功劳"。

八、最佳实践与安全指南

  1. 敏感信息不要放在 Cookie 里

Cookie 虽然方便,但不要明文存储密码、信用卡号等极敏感信息。应该存一个无意义的 Session ID,真正的用户数据放在服务端数据库中。

  1. 给 Cookie 加三道安全锁

    response.set_cookie(
    key="session_id",
    value="abc123",
    httponly=True, # 🔒 防 XSS:JS 读不到,只能浏览器发送
    secure=True, # 🔒 防窃听:仅 HTTPS 传输
    samesite="lax" # 🔒 防 CSRF:跨站请求不携带
    )

这三道锁是现代 Web 安全的基本防线。

  1. 使用 Token(JWT)替代 Cookie 做认证

在纯 API 服务(前后端分离)中,Cookie 依赖浏览器机制,移动端并不适用。更推荐在请求头中使用 Authorization: Bearer <JWT> 做认证,它是跨平台的。

  1. 区分"请求头解析失败"与"未登录"

请求头解析失败返回 422(参数错误),认证失败返回 401(未授权),权限不足返回 403(禁止)。语义要清晰,不要混用。

复制代码
@app.get("/admin")
async def admin_panel(authorization: str = Header(None)):
    if not authorization:
        raise HTTPException(401, "请先登录")
    if authorization != "Bearer secret_admin_token":
        raise HTTPException(403, "权限不足,需要管理员权限")
    return {"message": "欢迎管理员"}
  1. 不要依赖 Referer 做唯一安全验证

Referer 头可以被浏览器策略或用户设置禁用,也可能被伪造。只把它作为辅助参考,不要作为唯一的安全防线。

九、结语

对于普通 Web 用户而言,请求头和 Cookie 就是你和互联网服务之间那层看不见的"默契":

每次打开网页,浏览器都在背后默默递上你的"电子身份证"(请求头)。

每次点击"保持登录",浏览器都在本地存下你的"会员卡"(Cookie)。

它们像空气一样无处不在,却默默承载着认证、追踪、安全、缓存、内容协商等无数关键功能,让你每一次点击都能得到个性化的、安全的、快速的响应。

对于 FastAPI 开发者而言,Header 和 Cookie 是框架提供的两把轻量级钥匙。你无需手动解析原始请求字符串,只需在路由函数参数中声明你要读取的字段,框架就会自动提取、自动注入,让你用最少的代码,构建出最安全的身份识别系统。

相关推荐
IT_陈寒1 小时前
Vue的响应式更新把我坑惨了,原来是这个原因
前端·人工智能·后端
年轻的砖头1 小时前
以Ajax方式提交整个表单
前端·javascript·ajax
L-影2 小时前
FastAPI CORS 跨域:Web 世界的“小区门禁”与“访客通行证”
前端·javascript·fastapi
stereohomology2 小时前
已进入初赛提交Demo的两个项目:(2)单独html钢琴
前端·html·why不coding
源图客2 小时前
Claude Code基础使用
服务器·前端·数据库
asdzx672 小时前
在 React 中轻松实现 PDF 转 Word:纯前端 WASM 方案实战
前端·react.js·pdf
爱勇宝10 小时前
第 1 章:别把“需求文档”当成真正的需求
前端·后端·程序员
梨子同志11 小时前
常用命令
前端
梨子同志12 小时前
React 状态管理
前端