全栈视野学习Cookie——理解 Cookie 的本质

一、为什么需要 Cookie?

1. HTTP 的天生缺陷:无状态

HTTP 协议在设计之初便遵循"无状态"(Stateless)原则。所谓无状态,指的是服务器在处理请求时,不会记录客户端的任何历史信息------它不记得你是谁,也不记得你曾做过什么。每一次 HTTP 请求都是独立且孤立的。

这在实际应用中会带来什么问题?设想以下场景:

  • 你在电商网站将心仪的商品加入购物车,跳转至结算页面时,服务器却回应:"你是谁?你的购物车空空如也。"
  • 你刚刚成功登录,刷新页面后却被要求重新输入账号密码。

对服务器而言,每一次请求都像一位陌生访客的"初次见面"。这一设计在早期仅用于展示静态文档的 Web 中并无大碍,但随着现代 Web 应用承载起登录态、购物车、用户偏好等持续性状态,无状态就成了必须跨越的首要障碍。

2. 状态保持的需求

为了打破这一僵局,让服务器能够"记住"客户端,亟需一种机制来在多次 HTTP 请求间维持上下文 。其核心思路很简单:服务器为每位客户端分发一个唯一标识,客户端在后续每次请求中主动出示该标识,服务器便能轻松识别。

这个标识的具体载体,便是 Cookie。

一句话总结:HTTP 的无状态特性,催生了 Cookie 作为状态保持的基石。


二、Cookie 是什么?

1. 定义

Cookie 是浏览器存储的一小段文本数据,由服务器通过 HTTP 响应头下发给浏览器,浏览器保存后,在后续向同一服务器发起请求时自动将其携带回去。

拆解来看,三个关键点值得注意:

  • 浏览器存储:数据保存在客户端(浏览器),而非服务器端。
  • 一小段文本:单个 Cookie 的大小通常限制在 4KB 左右,不适合存放大量数据。
  • 每次请求自动携带 :这是 Cookie 区别于 localStorage 等其他存储方案的核心特征------无需开发者手动拼接,浏览器会自动将其附加在请求头中发送。

2. 一个直观的类比

不妨将 Cookie 类比为超市的会员卡

  • 首次光顾,你办理了一张会员卡(服务器下发 Cookie)。
  • 超市系统记录下卡号,同时你将实体卡带回家(浏览器存储 Cookie)。
  • 此后每次购物,你只需出示会员卡(请求自动携带 Cookie),收银员便能迅速识别你的身份和积分信息。

三、Cookie 的工作流程

Cookie 的完整生命周期可归纳为三个核心环节:

1. 第一步:服务端下发

服务器若希望在客户端种下 Cookie,会在 HTTP 响应中包含一个 Set-Cookie 头:

http 复制代码
HTTP/1.1 200 OK
Set-Cookie: sessionId=abc123; Path=/; HttpOnly

该响应头明确告知浏览器:请将键值对 sessionId=abc123 存储下来,作用于全站路径,并禁止 JavaScript 读取。

2. 第二步:浏览器存储

浏览器收到 Set-Cookie 指令后,会依据附带的属性(如 PathDomain 等)将其存入内部的 Cookie 存储区,并与对应的域名和路径相关联。

3. 第三步:后续请求自动携带

此后,浏览器每次向该服务器发送请求时,只要 Cookie 的 DomainPath 匹配,便会自动在请求头中附上该 Cookie:

http 复制代码
GET /user/profile HTTP/1.1
Host: example.com
Cookie: sessionId=abc123

整个流程可简化为以下时序图:

sequenceDiagram participant Browser as 浏览器 participant Server as 服务器 Note over Browser, Server: 第一步:服务端下发 Server->>Browser: &#34;HTTP/1.1 200 OK<br/>Set-Cookie: sessionId=abc123, Path=/, HttpOnly&#34; Note over Browser: 第二步:浏览器存储 Browser->>Browser: 存储 sessionId=abc123<br/>关联域名、路径,遵守 HttpOnly 等属性 Note over Browser, Server: 第三步:后续请求自动携带 Browser->>Server: &#34;GET /user/profile HTTP/1.1<br/>Cookie: sessionId=abc123&#34; Server-->>Browser: 响应

动手验证 :打开浏览器开发者工具(F12),在 Network 面板中观察任意请求的 Response Headers 和 Request Headers,你就能亲眼看到 Set-CookieCookie 这两个关键字段。

以无痕模式访问 www.baidu.com 为例:

  • 可见百度服务器下发了 6 条 Set-Cookie 响应头。
  • 注意此时请求头尚未携带 Cookie(首次访问)。
  • 小技巧:在 Network 面板中点击"Cookies"子选项卡,可以直观地查看本次请求下发了哪些 Cookie,以及后续请求携带了哪些 Cookie(若无 Cookie 传输,该选项卡可能不会显示)。
  • 此时浏览器已经存储了Cookie,往后的每次请求,只需要符合要求,Cookie便自动携带上。我们继续往下找,便可以找到一个请求标头带有Cookie的请求:
  • 同时,我们还可以从 应用程序->存储->Cookie 面板中查看浏览器对某域已经存储了的Cookie:

四、Cookie 的组成结构

一个完整的 Cookie 由两部分构成:键值对(name=value)属性(attributes)

1. 键值对(name=value)

这是 Cookie 的核心数据部分,格式为 名称=值。仍以百度首页响应中的 Set-Cookie 为例:

  • 名称与值均为字符串。
  • 若值中包含分号、逗号或空格等特殊字符,则需要进行 URL 编码。

2. 属性(元数据)

属性本身不参与数据存储,却决定了 Cookie 的作用边界安全策略。常见的属性列表如下:

属性 作用 示例
Domain 指定 Cookie 在哪些域名下生效 Domain=example.com
Path 指定 Cookie 在哪些路径下生效 Path=/app
Expires 设置过期时间(具体日期) Expires=Wed, 21 Oct 2026 07:28:00 GMT
Max-Age 设置有效时长(秒,相对时间) Max-Age=3600
Secure 标记后仅通过 HTTPS 连接传输 Secure
HttpOnly 标记后禁止 JavaScript 读取 HttpOnly
SameSite 控制跨站请求是否携带 Cookie SameSite=Lax

此外,现代浏览器的 Cookies 面板中通常还会展示 分区键(Partition Key)Cross Site (跨站标识)和 优先级(Priority) 等字段,便于开发者全方位诊断 Cookie 的作用域与行为细节。 这些属性在浏览器的Cookie调试面板中均可见:

http 复制代码
Set-Cookie: sessionId=abc123; Domain=example.com; Path=/; Max-Age=86400; HttpOnly; Secure; SameSite=Lax

逐项解读:

  • 键值对sessionId=abc123
  • Domain :作用于 example.com 及其子域
  • Path :作用于全站 /
  • Max-Age:有效期为 86400 秒(即 24 小时)
  • HttpOnly:禁止 JavaScript 读取
  • Secure:仅通过 HTTPS 传输
  • SameSite :设为 Lax(大多数跨站场景下不携带)
http 复制代码
Set-Cookie: BAIDUID=75EA0B9428BCEF18173F16D3E76A6B2A:FG=1; expires=Thu, 31-Dec-37 23:55:55 GMT; max-age=2147483647; path=/; domain=.baidu.com

逐项解读:

  • 键值对BAIDUID=75EA0B9428BCEF18173F16D3E76A6B2A:FG=1
  • Domain.baidu.com(涵盖 baidu.com 及其所有子域)
  • Path :全站 /
  • Max-Age / Expiresmax-age=2147483647 秒(约 68 年),配合久远的 expires,相当于持久化存储
  • Secure:未设置,因此非 HTTPS 连接也可传输
  • HttpOnly :未设置,JavaScript 可通过 document.cookie 读取
  • SameSite :未显式指定,现代浏览器通常采用默认值 Lax

要透彻理解 Cookie 的携带规则,必须先厘清三个基础概念:同源(Same-Origin)同站(Same-Site)跨站(Cross-Site)。许多关于 Cookie 的疑惑与误区,根源往往出在对这三者的混淆。

1. 同源(Same-Origin)

定义 :两个 URL 的协议(Scheme)、主机名(Host)和端口号(Port) 三者完全一致,方为同源。

判断示例:

URL A URL B 是否同源 原因
http://a.com/ http://a.com/user ✅ 同源 仅路径不同
http://a.com:3000 http://a.com:8080 ❌ 不同源 端口不同
http://a.com https://a.com ❌ 不同源 协议不同
http://a.com http://b.com ❌ 不同源 域名不同
http://a.com http://sub.a.com ❌ 不同源 子域名不同(被视作独立主机)

2. 同站(Same-Site)

定义 :若两个 URL 的 eTLD+1(有效顶级域名 + 一级域名)相同,则视为同站。端口和协议不影响同站判断。

eTLD 是 "effective Top-Level Domain" 的缩写,由 Public Suffix List 维护。简言之,.com.org 属于 TLD,而 .com.cn.github.io 整体视作一个 eTLD。

判断示例:

URL A URL B 是否同站
http://a.com https://a.com ✅ 同站(协议无关)
http://a.com:3000 http://a.com:8080 ✅ 同站(端口无关)
http://sub.a.com http://a.com ✅ 同站(eTLD+1 均为 a.com
http://a.com http://b.com ❌ 跨站
http://a.github.io http://b.github.io ❌ 跨站(eTLD 为 github.io

3. 三者关系

三者的范围可概括为:

复制代码
跨站 ⊃ 同站 ⊃ 同源

换言之:同源一定同站,但同站未必同源(端口或协议不同时)。而跨站则意味着 eTLD+1 都不相同。

Cookie 的携带规则受 DomainPathSameSite 属性的综合约束:

  • DomainPath 定义了 Cookie 的"作用范围"------哪些 URL 有权使用它。
  • SameSite 则决定了在"跨站"场景下,是否允许浏览器发送该 Cookie。

关键规则速查:

SameSite 值 同站请求 跨站请求
Strict ✅ 携带 ❌ 不携带
Lax(默认) ✅ 携带 ⚠️ 部分携带(仅限顶级导航 GET 请求)
None ✅ 携带 ✅ 携带(必须同时设置 Secure

这段规则的现实意义非常直接 :若你的前后端部署在不同域名下(跨站),即使 Domain 设置正确,只要 SameSite=LaxStrict,Cookie 便不会被发送。唯有显式设置为 SameSite=None; Secure 方可跨站携带------而这又强制要求使用 HTTPS。

相关推荐
前端开发呀43 分钟前
我的 AI 终端配置清单
前端
敲代码的玉米C1 小时前
测试一直在写你的真实数据根
前端·人工智能·架构
执子念的飞鱼1 小时前
File Viewer 进入 2K 节点后,我更在意这 3 条回归
前端·typescript
richdata1 小时前
动态OTB vs 静态OTB:鞋服零售该选哪种管理模式?
前端·html·零售
Jodie同志1 小时前
第16~23天:持久化、HITL、流式、MCP与安全
前端·后端·agent
Jodie同志2 小时前
第1~15天:原生Agent、RAG与LangGraph基础(完整代码实操)
前端·后端·agent
sunly_2 小时前
React useActionState 的用法详解
前端·javascript·react.js
今日无bug2 小时前
RESTful + Interface:从 todos 项目理解后端接口设计
前端·restful
用户69371750013842 小时前
#DeepSeek+Pi‑Agent 王炸组合跑赢 Claude‑Code!
前端·人工智能·后端