HTTP 核心:请求响应、缓存、CORS 与 HTTP/2/3
前端必须掌握的 HTTP 知识体系——方法、状态码、Headers、缓存策略、跨域、协议演进
1. 请求/响应模型
客户端(浏览器) 服务端
│ │
│ ──── 请求(Request)────→ │
│ │
│ ←──── 响应(Response)──── │
│ │
无状态协议: 每次请求独立,服务端不记住上一次请求。需要状态就用 Cookie / Token / Session。
2. HTTP 方法
GET 获取资源 幂等(多次请求结果一样)
POST 创建资源 非幂等
PUT 替换资源 幂等
PATCH 部分更新 非幂等
DELETE 删除资源 幂等
HEAD 只要响应头 幂等
OPTIONS 预检请求 CORS 用
幂等性: 同一个请求发 1 次和发 10 次,服务端状态一致。GET 天然幂等,POST 不是。
3. 状态码
2xx 成功
200 OK 请求成功
201 Created 资源创建成功(POST 之后)
204 No Content 删除成功,无返回体
3xx 重定向
301 Moved Permanently 永久重定向(SEO 友好)
302 Found 临时重定向
304 Not Modified 缓存命中,不需要重新请求
4xx 客户端错误
400 Bad Request 请求格式错误
401 Unauthorized 未认证(没有 Token)
403 Forbidden 无权限
404 Not Found 资源不存在
429 Too Many Requests 请求频率超限
5xx 服务端错误
500 Internal Server Error 服务端崩了
502 Bad Gateway 网关错误
503 Service Unavailable 服务不可用
4. Headers
请求头:
Accept: application/json 期望的响应格式
Content-Type: application/json 发送的数据格式
Authorization: Bearer <token> 认证令牌
Cache-Control: no-cache 缓存策略
If-None-Match: "abc123" 协商缓存(ETag)
If-Modified-Since: Wed, 21 Oct... 协商缓存(Last-Modified)
Origin: https://example.com 来源(CORS 用)
响应头:
Content-Type: application/json 响应数据格式
Cache-Control: max-age=3600 缓存策略
ETag: "abc123" 资源版本标识
Last-Modified: Wed, 21 Oct... 最后修改时间
Access-Control-Allow-Origin: * CORS 允许的来源
Set-Cookie: token=xxx 设置 Cookie
5. 缓存
强缓存: 浏览器直接用本地缓存,不发请求。
Cache-Control: max-age=3600 相对时间(推荐)
Expires: Wed, 21 Oct 2025... 绝对时间(已废弃)
协商缓存: 带条件请求服务端,没变就返回 304(不传 body)。
// 第一次请求
ETag: "v2" 服务端返回资源标识
Last-Modified: Wed, 21 Oct... 服务端返回修改时间
// 第二次请求(带上条件)
If-None-Match: "v2"
If-Modified-Since: Wed, 21 Oct...
// 服务端比较
// 没变 → 304 Not Modified(不用重新传 body)
// 变了 → 200 + 新资源
优先级: Cache-Control: no-cache \> ETag \> Last-Modified
no-cache vs no-store:**
no-cache 每次都要跟服务端验证(协商缓存)
no-store 完全不缓存
6. CORS(跨域)
同源策略: 协议 \+ 域名 \+ 端口都相同才算同源。不同源的请求被浏览器拦截。
简单请求: GET/POST/HEAD \+ 简单 Header → 直接发,服务端返回 Access-Control-Allow-Origin。
预检请求(Preflight):
浏览器发现是复杂请求(PUT/DELETE/自定义 Header/JSON body)
↓
先发 OPTIONS 请求(预检)
↓
服务端返回:
Access-Control-Allow-Origin: https://example.com
Access-Control-Allow-Methods: GET, POST, PUT, DELETE
Access-Control-Allow-Headers: Content-Type, Authorization
Access-Control-Max-Age: 86400 (预检结果缓存 24 小时)
↓
浏览器确认允许 → 发真正请求
7. HTTP/2 vs HTTP/3
HTTP/1.1:
- 一个连接一个请求(队头阻塞)
- Keep-Alive 复用连接,但还是串行
HTTP/2:
- 多路复用:一个连接上并行多个请求(二进制分帧)
- 头部压缩:HPACK 算法
- 服务端推送:主动推资源
- 缺点:TCP 层的队头阻塞还在
HTTP/3:
- QUIC 协议(基于 UDP)
- 彻底解决队头阻塞
- 0-RTT 连接建立
- 连接迁移(Wi-Fi → 4G 不断线)
8. fetch \+ AbortController
const controller = new AbortController()
fetch('/api/data', { signal: controller.signal })
.then(res => res.json())
.then(data => console.log(data))
.catch(err => {
if (err.name === 'AbortError') console.log('请求取消了')
})
// 组件卸载时取消请求
useEffect(() => {
const controller = new AbortController()
fetchData({ signal: controller.signal })
return () => controller.abort()
}, [])
跟 TanStack Query 的关系: TanStack Query 内部就是用 AbortController 管理请求取消的,组件卸载时自动 abort。
核心一句话
HTTP 是无状态的请求/响应协议。缓存靠 Cache-Control \+ ETag,跨域靠 CORS 预检,实时通信靠 WebSocket/SSE,请求取消靠 AbortController。