Skip to content

HTTP ​

导航目录 ​

基础篇 ​

缓存篇 ​

跨域篇 ​

安全篇 ​

协议演进篇 ​


HTTP 协议特点 ​

核心概念

HTTP(超文本传输协议)是应用层协议,基于 TCP/IP,采用请求-响应模型,是 Web 通信的基石。其几个核心特性决定了它的行为方式。

特点说明
简单快速只需传送请求方法和路径(GET/POST/HEAD 等),服务器程序规模小、速度快
灵活可传输任意类型数据,类型由 Content-Type 标记
无连接每次连接只处理一个请求,处理完即断开(HTTP/1.1 起用长连接优化)
无状态协议对事务处理无记忆能力,需借助 Cookie/Session/Token 维持状态
支持 B/S、C/S适用于浏览器-服务器、客户端-服务器架构

无状态的解决

由于 HTTP 无状态,登录态等场景需要额外机制:Cookie(客户端存储)、Session(服务端存储 + Cookie 携带 sessionId)、Token(如 JWT,服务端无状态校验)。


HTTP 报文的组成部分 ​

核心概念

HTTP 报文分请求报文与响应报文,均由「起始行 + 头部 + 空行 + 主体」四部分组成。空行是头部与主体的分隔标志,不可省略。

请求报文 ​

GET /hu.jpg HTTP/1.1              // 请求行:方法 + 资源路径 + 协议版本
Host: example.com                 // 请求头部:附加信息
User-Agent: Mozilla/5.0 ...
                                  // 空行(必须,标志头部结束)
name=zhangsan&age=18              // 请求主体(GET 通常为空)

响应报文 ​

HTTP/1.1 200 OK                   // 状态行:协议版本 + 状态码 + 状态短语
Content-Type: application/json    // 响应头部
Content-Length: 27
                                  // 空行
{ "code": 0, "data": {} }         // 响应主体

说明

Host 指出请求目的地;User-Agent 标识客户端类型,是浏览器检测的基础;即使主体为空,头部后的空行也必须存在。


HTTP 状态码 ​

核心概念

状态码是服务器对请求处理结果的三位数字表示,首位数字标识类别。掌握常见状态码有助于快速定位问题。

类别含义
1xx指示信息:请求已接收,继续处理
2xx成功:请求已被成功接收、理解、处理
3xx重定向:需进一步操作以完成请求
4xx客户端错误:请求语法错误或无法实现
5xx服务端错误:服务器未能实现合法请求

常见状态码

状态码含义
200 OK请求成功
201 Created资源已创建(POST/PUT 成功)
204 No Content成功但无返回内容
206 Partial Content部分内容(断点续传、分片)
301 Moved Permanently永久重定向(SEO 会转移权重)
302 Found临时重定向
304 Not Modified资源未修改,使用协商缓存
400 Bad Request请求语法错误
401 Unauthorized未认证(需登录)
403 Forbidden已认证但无权限
404 Not Found资源不存在
500 Internal Server Error服务器内部错误
502 Bad Gateway网关错误(上游服务异常)
503 Service Unavailable服务暂时不可用(过载/维护)
504 Gateway Timeout网关超时

易混辨析

301 vs 302:前者永久(浏览器会缓存新地址);后者临时。401 vs 403:前者"你是谁"(未登录),后者"你没权限"(已登录但被拒)。


GET、POST 区别 ​

核心概念

GET 与 POST 是最常用的两种请求方法,本质都是基于 TCP 的 HTTP 请求,区别更多是「语义约定」与「浏览器/服务器实现习惯」,而非协议强制。

维度GETPOST
语义获取资源(读)提交数据(写)
参数位置URL 查询字符串请求主体 body
参数长度受 URL 长度限制(浏览器/服务器约束)理论无限制
缓存会被浏览器主动缓存默认不缓存
幂等性幂等(多次请求结果一致)非幂等
安全性参数暴露在 URL,易被记录参数在 body,相对隐蔽
数据包通常一个 TCP 包部分浏览器分两次发(先 header 后 body)

安全性澄清

POST 并非真正"安全"——body 同样是明文。真正的安全依赖 HTTPS 加密,而非选用 POST。


长连接与短连接 ​

核心概念

HTTP 的长/短连接本质是底层 TCP 连接的复用与否。长连接减少了反复建立/关闭 TCP 连接(三次握手四次挥手)的开销。

类型说明
短连接HTTP/1.0 默认。每次 HTTP 操作都新建一次 TCP 连接,请求结束即断开。页面中每个资源都要重新建连
长连接HTTP/1.1 默认。通过 Connection: keep-alive 复用 TCP 连接,页面加载完后连接不立即关闭,后续请求继续复用

要点

Keep-Alive 有超时时间(可在 Nginx/Apache 配置),并非永久保持;长连接需客户端与服务端都支持。HTTP 的长短连接实质是 TCP 的长短连接。


HTTP 缓存架构图 ​

核心概念

HTTP 缓存分为「强缓存」与「协商缓存」。浏览器请求资源时先查强缓存,命中则直接用本地副本(不发请求);未命中再走协商缓存,向服务器询问资源是否更新。

HTTP 缓存

整体流程

  1. 浏览器请求资源,先检查强缓存(Cache-Control / Expires)。
  2. 强缓存有效 → 直接使用本地缓存,状态码 200 (from disk/memory cache),不发请求。
  3. 强缓存失效 → 发起请求进入协商缓存,携带 If-Modified-Since / If-None-Match。
  4. 服务器判断资源是否变化:未变化返回 304,用本地缓存;变化返回 200 + 新资源。

内存缓存 vs 磁盘缓存

from memory cache:读取快、随进程释放(如刷新时的图片/脚本);from disk cache:持久化到磁盘,容量大、速度稍慢。


Last-Modified & ETag ​

核心概念

两者都是协商缓存的校验依据。Last-Modified 基于文件最后修改时间,ETag 基于文件内容生成的唯一标识(哈希)。ETag 优先级更高,用于弥补 Last-Modified 的精度缺陷。

对比项Last-ModifiedETag
依据文件最后修改时间文件内容指纹(哈希等)
请求头If-Modified-SinceIf-None-Match
响应头Last-ModifiedETag
精度秒级(1 秒内多次修改无法识别)内容级,精确
缺陷内容不变仅时间变时会误判计算有性能开销

校验流程

① 首次请求 → 响应头带 Last-Modified / ETag
② 再次请求 → 请求头带 If-Modified-Since / If-None-Match
③ 服务器比对:未变 → 304 Not Modified;已变 → 200 + 新资源与新标识

注意

若同时存在 ETag 和 Last-Modified,服务器会优先校验 ETag。周期性重写但内容不变的文件(如构建产物),应依赖 ETag 避免误判。


强缓存与协商缓存 ​

核心概念

强缓存不与服务器交互,直接用本地缓存;协商缓存需向服务器发请求确认。二者是「先强后协商」的层级关系。

类型强缓存协商缓存
是否发请求否是(询问是否更新)
相关头Cache-Control、ExpiresETag/If-None-Match、Last-Modified/If-Modified-Since
命中状态码200 (from cache)304 Not Modified

Cache-Control 常用值

值含义
max-age=秒缓存有效时长(相对时间,优先级高于 Expires)
no-cache不用强缓存,每次走协商缓存
no-store完全不缓存
public可被浏览器、代理服务器缓存
private仅浏览器可缓存

Expires vs Cache-Control

Expires 是 HTTP/1.0 产物,值为绝对时间(受客户端时间影响不可靠);Cache-Control: max-age 是 HTTP/1.1 相对时间,优先级更高,推荐使用。


刷新操作对缓存的影响 ​

核心概念

不同的刷新方式对缓存的处理策略不同,理解这点有助于调试缓存问题。

操作强缓存协商缓存
地址栏回车 / 前进后退生效生效
普通刷新(F5)失效生效
强制刷新(Ctrl+F5)失效失效

说明

普通刷新会跳过强缓存,直接发协商请求(多为 304);强制刷新会带 Cache-Control: no-cache,强、协商缓存都失效,全部资源重新拉取。


同源策略 ​

核心概念

同源策略(Same-Origin Policy)是浏览器最核心的安全机制。「同源」指协议、域名、端口三者完全相同。它限制一个源的文档/脚本与另一个源的资源交互,防止 XSS、CSRF 等攻击。

对比 URL是否同源原因
http://a.com/a.js vs http://a.com/b.js同源协议、域名、端口一致
http://a.com vs https://a.com不同源协议不同
http://a.com vs http://b.com不同源域名不同
http://a.com:80 vs http://a.com:8080不同源端口不同

记忆

同源三要素:协议 + 域名 + 端口,缺一不可。子域名(a.com vs www.a.com)也算不同源。


跨域请求限制 ​

核心概念

同源策略限制的是「读取」跨域资源的能力,而非「发送」请求。请求通常能发出去,只是响应被浏览器拦截。

同源策略主要限制以下三类行为:

  • DOM 访问受限:无法读取不同源 iframe 的 DOM。
  • 数据读取受限:无法读取不同源的 Cookie、LocalStorage、IndexedDB。
  • 网络请求受限:AJAX(XHR/fetch)请求可以发出,但响应会被浏览器拦截,JS 无法读取。

常见误解

跨域请求其实已到达服务器并被处理(后端能收到),只是浏览器基于同源策略拦截了响应,导致前端拿不到数据。所以跨域是浏览器行为,不是服务端行为。


不受同源策略限制的情况 ​

核心概念

部分标签天然允许跨域加载资源,这也是 JSONP 等早期跨域方案的原理基础。

场景说明
<img>图片跨域加载(打点统计常用)
<script>脚本跨域加载(JSONP 原理)
<link>CSS、字体等跨域加载
<video> / <audio>媒体资源跨域
跳转/表单提交页面跳转、<form> 提交不受限

JSONP 原理

利用 <script> 可跨域的特性,前端定义回调函数,服务端返回 callback(data) 形式的脚本执行。缺点:只支持 GET、安全性差,现已被 CORS 取代。


CORS 跨域完整流程 ​

核心概念

CORS(跨域资源共享)是 W3C 标准的跨域方案,通过服务端设置响应头告诉浏览器「允许该源访问」。请求分为「简单请求」与「非简单请求(需预检)」两类。

简单请求 ​

同时满足以下条件即为简单请求,浏览器直接发送并在请求头带 Origin:

  • 方法为 GET / POST / HEAD。
  • 请求头仅限安全字段(Accept、Content-Type 等)。
  • Content-Type 仅为 text/plain、multipart/form-data、application/x-www-form-urlencoded。
① 浏览器请求
GET /api/data HTTP/1.1
Origin: http://a.com

② 服务器响应(关键 CORS 头)
Access-Control-Allow-Origin: http://a.com   // 或 *
Access-Control-Allow-Credentials: true       // 允许带 Cookie 时

非简单请求(预检) ​

不满足简单请求条件(如 PUT/DELETE、Content-Type: application/json、自定义头),浏览器会先发 OPTIONS 预检请求:

① 预检请求(浏览器自动发起)
OPTIONS /api/data HTTP/1.1
Origin: http://a.com
Access-Control-Request-Method: PUT
Access-Control-Request-Headers: Content-Type, Authorization

② 预检响应
Access-Control-Allow-Origin: http://a.com
Access-Control-Allow-Methods: GET, POST, PUT, DELETE
Access-Control-Allow-Headers: Content-Type, Authorization
Access-Control-Max-Age: 86400                 // 预检结果缓存时间

③ 预检通过后,才发送真实请求

服务端设置示例(Node.js / Express)

js
app.use((req, res, next) => {
  res.header("Access-Control-Allow-Origin", "http://a.com");
  res.header("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE, OPTIONS");
  res.header("Access-Control-Allow-Headers", "Content-Type, Authorization");
  res.header("Access-Control-Allow-Credentials", "true"); // 允许携带 Cookie
  if (req.method === "OPTIONS") return res.sendStatus(204); // 预检直接返回
  next();
});

携带 Cookie 的限制

当 Access-Control-Allow-Credentials: true 时,Access-Control-Allow-Origin 不能为 *,必须指定具体源;前端也需设置 xhr.withCredentials = true 或 fetch(url, { credentials: 'include' })。


跨域预检请求优化 ​

核心概念

非简单请求每次都会先发一次 OPTIONS 预检,增加了一次往返开销。可通过 Access-Control-Max-Age 缓存预检结果,减少重复预检。

Nginx 配置示例

nginx
location /api/ {
  add_header Access-Control-Allow-Origin $http_origin;
  add_header Access-Control-Allow-Methods 'GET, POST, PUT, DELETE, OPTIONS';
  add_header Access-Control-Allow-Headers 'Content-Type, Authorization';
  add_header Access-Control-Allow-Credentials true;
  add_header Access-Control-Max-Age 86400;   # 预检结果缓存 1 天

  # 预检请求直接返回 204,不转发到后端
  if ($request_method = 'OPTIONS') {
    return 204;
  }
  proxy_pass http://backend;
}

优化要点

  1. 用 Access-Control-Max-Age 缓存预检结果(浏览器有效期内不再预检)。
  2. 尽量让请求满足「简单请求」条件,避免触发预检。
  3. 在网关/Nginx 层统一处理 CORS,避免每个后端服务重复配置。

HTTP 对比 HTTPS ​

核心概念

HTTPS = HTTP + SSL/TLS。它在 HTTP 与 TCP 之间加了一层加密(TLS),解决了 HTTP 明文传输带来的窃听、篡改、冒充问题。

对比项HTTPHTTPS
传输明文加密(TLS)
端口80443
证书无需需 CA 证书
安全性易被窃听/篡改加密 + 身份认证 + 完整性校验
性能无加密开销握手有额外开销(可用会话复用优化)

HTTPS 三大保障

加密性(防窃听)、完整性(防篡改)、身份认证(防冒充)。三者共同构成安全通信基础。


对称加密 ​

核心概念

对称加密指加密和解密使用同一把密钥。特点是速度快、效率高,适合加密大量数据。常见算法:AES、DES、3DES。

明文 --(密钥 K 加密)--> 密文 --(密钥 K 解密)--> 明文

核心痛点

对称加密的难点在于密钥分发:通信双方如何在不安全的网络中安全地交换这把密钥?若密钥在传输中被截获,加密即失效。这正是需要非对称加密的原因。


非对称加密 ​

核心概念

非对称加密使用一对密钥:公钥(公开)和私钥(保密)。公钥加密的数据只能用私钥解密,反之亦然。解决了密钥分发问题,但速度慢。常见算法:RSA、ECC。

公钥加密 → 私钥解密   (用于加密数据,只有私钥持有者能解)
私钥加密 → 公钥解密   (用于数字签名,验证发送方身份)

HTTPS 的组合方案

HTTPS 结合两者:用非对称加密安全地传递对称密钥,之后的通信用对称加密(快)。即"非对称协商密钥 + 对称传输数据",兼顾安全与性能。


为什么有非对称加密还需要 CA 证书 ​

核心概念

非对称加密解决了密钥分发,但无法解决"公钥是否可信"的问题——中间人可以伪造公钥。CA(证书颁发机构)通过数字证书为公钥的归属做权威背书。

没有 CA 的漏洞(中间人攻击)

客户端 →(索要公钥)→ 中间人(掉包成自己的公钥)→ 服务器
之后客户端用的是中间人的公钥,通信全被中间人解密/篡改

CA 证书的作用

  1. 服务器把公钥等信息交给 CA,CA 用自己的私钥签名生成证书。
  2. 浏览器内置了受信任 CA 的公钥,可验证证书签名的真伪。
  3. 验证通过即确认「这个公钥确实属于该网站」,中间人无法伪造(没有 CA 私钥)。

关键

CA 证书本质是「用 CA 私钥对网站公钥的签名」。浏览器信任链:根 CA → 中间 CA → 网站证书。任何一环校验失败都会提示"不安全"。


HTTPS 的 TLS 握手过程 ​

核心概念

TLS 握手是 HTTPS 建立安全连接的关键步骤,目的是验证身份并协商出对称密钥。以下为经典 RSA 密钥交换流程(TLS 1.2)。

text
客户端                                                服务器
   |  1. Client Hello(TLS版本、加密套件、随机数1)    |
   | ───────────────────────────────────────────────► |
   |  2. Server Hello(选定版本、加密套件、随机数2)    |
   | ◄─────────────────────────────────────────────── |
   |  3. 发送 CA 证书(含服务器公钥)                   |
   | ◄─────────────────────────────────────────────── |
   |  [4. 客户端校验证书合法性]                         |
   |  5. 用公钥加密预主密钥发送                          |
   | ───────────────────────────────────────────────► |
   |  [双方用 随机数1+随机数2+预主密钥 生成会话密钥]     |
   |  6. Finished(用会话密钥加密)                     |
   | ───────────────────────────────────────────────► |
   |  7. Finished(用会话密钥加密)                     |
   | ◄─────────────────────────────────────────────── |
   |  [之后用对称会话密钥加密通信]                       |

核心步骤说明

  1. 客户端发送支持的加密套件与随机数(Client Random)。
  2. 服务器选定加密套件,回传随机数(Server Random)+ CA 证书。
  3. 客户端校验证书,生成"预主密钥"(Pre-Master Secret),用服务器公钥加密后发送。
  4. 双方根据两个随机数 + 预主密钥,各自计算出相同的会话密钥(对称密钥)。
  5. 之后所有通信用会话密钥对称加密。

TLS 1.3 优化

TLS 1.3 简化握手,仅需 1-RTT(甚至 0-RTT 会话恢复),并废弃不安全的算法,改用 ECDHE 前向安全的密钥交换,握手更快更安全。


HTTPS 中间人攻击 ​

核心概念

中间人攻击(MITM)指攻击者插入通信双方之间,冒充双方转发/篡改数据。HTTPS 通过 CA 证书体系防御,但在特定场景仍可能被攻破。

攻击方式

  • 证书伪造:攻击者伪造证书,若浏览器无内置对应 CA 则会告警。
  • SSL 剥离:把 HTTPS 降级为 HTTP,诱导明文通信。
  • 诱导安装根证书:让用户手动信任攻击者的根证书(抓包工具如 Charles/Fiddler 原理)。

防御手段

手段说明
CA 证书校验浏览器验证证书链,非法证书告警
HSTS强制浏览器只用 HTTPS,防降级
证书锁定(Pinning)App 内固定合法证书指纹
不随意信任根证书避免安装来源不明的根证书

抓包原理

Charles/Fiddler 抓 HTTPS 包,本质就是"合法的中间人"——需要你手动安装它的根证书,让浏览器信任其伪造的证书,从而解密流量。这也说明保护根证书信任列表的重要性。


HTTP 2.0 的优势 ​

核心概念

HTTP/2 基于 SPDY,在不改变 HTTP 语义的前提下大幅提升性能,核心是「二进制分帧」,解决了 HTTP/1.1 的性能瓶颈。

特性说明
二进制分帧报文拆成二进制帧传输,解析更高效、无歧义
多路复用同一 TCP 连接并行传输多个请求/响应,解决队头阻塞(应用层)
头部压缩(HPACK)压缩冗余头部,减少传输量
服务器推送服务器可主动推送客户端可能需要的资源
请求优先级可为流设置优先级,重要资源优先传输

对比 HTTP/1.1

HTTP/1.1 靠「多个 TCP 连接 + 长连接 + 管线化」优化,但受浏览器并发连接数限制(约 6 个)且有队头阻塞。HTTP/2 单连接即可高效并发。


HTTP 2 的多路复用 ​

核心概念

多路复用(Multiplexing)指在一个 TCP 连接上同时发送多个请求和响应,互不干扰。这是 HTTP/2 相比 HTTP/1.1 的最大改进。

实现原理

  • 流(Stream):一个双向字节流,对应一个请求/响应对,有唯一 ID。
  • 消息(Message):一个完整的请求或响应,由多个帧组成。
  • 帧(Frame):最小传输单位,带有所属流的标识。

HTTP/1.1:请求需排队(一个连接同一时间一个请求)
连接 1: [请求 A]--------[请求 B]--------[请求 C]

HTTP/2:多个流的帧交错在同一连接传输
连接 1: [A 帧][B帧][A 帧][C帧][B 帧][C帧] → 按流 ID 重组

效果

多路复用消除了 HTTP/1.1 的「应用层队头阻塞」,一个连接即可并发大量请求,减少连接建立开销与资源占用。


队头阻塞问题 ​

核心概念

队头阻塞(Head-of-Line Blocking)指队列中第一个数据被阻塞,导致后续数据全部等待。HTTP 演进史很大程度就是解决队头阻塞的历史。

层级队头阻塞是否解决
HTTP/1.1 应用层一个连接同一时间只能处理一个请求,前一个不完成后面排队HTTP/2 多路复用解决
TCP 传输层TCP 需按序交付,丢一个包后面所有包都要等重传HTTP/2 仍存在,HTTP/3 用 QUIC 解决

HTTP/2 的遗留问题

HTTP/2 解决了应用层队头阻塞,但底层仍是 TCP。一旦某个 TCP 包丢失,整个连接上所有流都要等待重传——这就是 TCP 层队头阻塞。这也是 HTTP/3 改用 UDP(QUIC)的根本原因。


HTTP 3 与 QUIC ​

核心概念

HTTP/3 最大变革是传输层从 TCP 换成基于 UDP 的 QUIC 协议,彻底解决了 TCP 层队头阻塞,并优化了连接建立速度。

特性说明
基于 UDP(QUIC)在 UDP 上自行实现可靠传输、拥塞控制
无 TCP 队头阻塞各流独立,一个流丢包不影响其他流
0-RTT / 1-RTT 建连合并传输握手与 TLS 握手,首次 1-RTT,恢复 0-RTT
连接迁移用 Connection ID 标识连接,切换网络(WiFi↔4G)不断连
内置 TLS 1.3加密是 QUIC 的一部分,默认安全

HTTP/1.1 → HTTP/2 → HTTP/3
TCP TCP QUIC(UDP)
明文/TLS TLS 内置 TLS1.3
应用层阻塞 TCP 层阻塞 无队头阻塞

连接迁移

QUIC 用 Connection ID 而非「IP+端口」标识连接,因此手机从 WiFi 切到 4G 时连接不中断,视频/直播场景体验更好。


TCP 和 UDP 区别 ​

核心概念

TCP 与 UDP 都是传输层协议。TCP 面向连接、可靠有序;UDP 无连接、不可靠但高效。选择取决于对可靠性与实时性的权衡。

对比项TCPUDP
连接面向连接(三次握手)无连接
可靠性可靠(确认、重传、排序)不可靠(尽力而为)
顺序保证有序不保证
速度较慢(开销大)快(开销小)
头部开销20 字节起8 字节
传输方式字节流数据报
适用场景HTTP、文件传输、邮件视频直播、DNS、游戏、QUIC

记忆

TCP 像"打电话"(先建连、可靠有序);UDP 像"发短信/广播"(发出即走,不管对方收没收到)。


TCP 三次握手与四次挥手 ​

核心概念

三次握手用于建立连接,确认双方收发能力正常;四次挥手用于断开连接,确保双方数据都发送完毕。

三次握手(建立连接) ​

text
客户端                                        服务器
   |  1. SYN=1, seq=x(我要连你)              |
   | ───────────────────────────────────────► |
   |  2. SYN=1, ACK=1, seq=y, ack=x+1(我也要连你)|
   | ◄─────────────────────────────────────── |
   |  3. ACK=1, ack=y+1(确认,开始通信)      |
   | ───────────────────────────────────────► |

为什么是三次? 两次无法确认「客户端的接收能力」和「服务端的发送能力」。三次才能保证双方收发能力都正常,防止已失效的连接请求突然到达导致误连。

四次挥手(断开连接) ​

text
客户端                                 服务器
   |  1. FIN=1, seq=u(我没数据要发了)   |
   | ─────────────────────────────────► |
   |  2. ACK=1, ack=u+1(知道了)         |
   | ◄───────────────────────────────── |
   |  3. FIN=1, seq=w(我也发完了)       |
   | ◄───────────────────────────────── |
   |  4. ACK=1, ack=w+1(确认,等 2MSL)  |
   | ─────────────────────────────────► |

为什么是四次? 服务端收到 FIN 后可能还有数据要发,所以「确认」和「关闭」分两步发送,比握手多一次。

TIME_WAIT 状态

客户端最后需等待 2MSL(最大报文段生存时间)才关闭,目的是:① 确保最后的 ACK 到达服务端;② 让本次连接的旧报文在网络中消散,避免影响新连接。