HTTP
浏览器与服务器之间通信的应用层协议,建立在TCP之上,是一个请求-响应协议,用于客户端和服务端之间的通信。
访问网页的时候就会用到 HTTP、举个例子,当你想要访问一个网站时:
1、浏览器本身是一个客户端,当你输入 URL 的时候,首先浏览器会去请求 DNS 服务器,通过 DNS 获取相应的域名对应的 IP
2、通过 IP 地址找到 IP 对应的服务器后,要求建立 TCP 连接,等浏览器发送完 HTTP Request(请求)包后,服务器接收到请求包之后才开始处理请求包,服务器调用自身服务,返回 HTTP Response(响应)包
3、客户端收到来自服务器的响应后开始渲染这个 Response 包里的主体(body),等收到全部的内容随后断开与该服务器之间的 TCP 连接。
| 
|
| ------------------------------------------------------------ |
HTTP请求包(请求报文)
一个 HTTP 请求由 3 部分组成:
bash
请求行(Request Line) 包含方法(GET,POST等)、路径、协议版本 # GET /index.html HTTP/1.1
请求头(Headers)常见请求头:Host、User-Agent、Accept、Cookie、Authorization、Content-Type、Content-Length
// 空格
请求体(Body) 一般是JSON、表单、文件上传
下面是一个示例:
bash
GET /domains/example/ HTTP/1.1 # 请求行: 请求方法 请求 URI HTTP 协议/协议版本
Host:www.iana.org # 服务端的主机名
User-Agent:Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.4 (KHTML, like Gecko) Chrome/22.0.1229.94 Safari/537.4 # 浏览器信息
Accept:text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8 # 客户端能接收的 mine
Accept-Encoding:gzip,deflate,sdch #是否支持流压缩
Accept-Charset:UTF-8,*;q=0.5 #客户端字符编码集
# 空行,用于分割请求头和消息体
# 消息体,请求资源参数,例如 POST 传递的参数
username=johndoe&password=123456 # 表单信息示例 、键值对用 & 连接、键和值用 = 连接、特殊字符会被URL编码
# JSON信息示例
{
"name": "John Doe",
"email": "john@example.com",
"age": 30
}
常见HTTP方法及其语义
| 方法 | 描述 | 是否安全 | 是否幂等 | 是否有请求体 |
|---|---|---|---|---|
| GET | 获取资源 | ✅ | ✅ | ❌ |
| POST | 提交数据(新增) | ❌ | ❌ | ✅ |
| PUT | 更新资源(整体) | ❌ | ✅ | ✅ |
| PATCH | 部分更新资源 | ❌ | ✅ | ✅ |
| DELETE | 删除资源 | ❌ | ✅ | ❌ |
| HEAD | 获取资源元信息 | ✅ | ✅ | ❌ |
| OPTIONS | 查看服务器支持哪些方法 | ✅ | ✅ | ❌ |
"安全"表示不会修改服务器状态
"幂等"表示多次执行效果相同
GET 和 POST 的本质区别:
| GET | POST | |
|---|---|---|
| 数据位置 | URL 之后、以 ? 分割URL和数据,参数间以 & 相连 |
请求体 body中 |
| 数据大小 | 较小(浏览器对URL 长度限制) | 较大(没限制) |
| 语义安全 | 安全、幂等、用于读取资源 | 不安全、非幂等、用于创建/提交数据 |
上面的语义安全不是信息安全,相反GET提交数据,信息不安全。
比如一个登录页面,通过 GET 方式提交数据时,用户名和密码将出现在 URL 上,如果页面可以被缓存或者其他人可以访问这台机器,就可以从历史记录获得该用户的账号和密码。
HTTP响应包(响应报文)
响应也包含 3 部分:
bash
状态行(Status Line)# HTTP/1.1 200 OK
响应头(Headers)常见响应头:、Content-Type、Content-Length、Cache-Control、Set-Cookie、Server
响应体(Body)一般是 HTML、JSON、图片、视频等
下面是一个示例:
bash
HTTP/1.1 200 OK # 状态行
Server: nginx/1.0.8 # 服务器使用的 WEB 软件名及版本
Date: Tue, 30 Oct 2012 04:14:25 GMT # 发送时间
Content-Type: text/html # 服务器发送信息的类型
Transfer-Encoding: chunked # 表示发送 HTTP 包是分段发的
Connection: keep-alive # 保持连接状态
Content-Length: 90 # 主体内容长度
// 空行 用来分割消息头和主体
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"... // 消息体
状态码
状态码用来告诉 HTTP 客户端,HTTP 服务器是否产生了预期的 Response,常见的状态码有5类:
| 状态码 | 信息 | 含义 |
|---|---|---|
| 1XX | 提示信息 | 表示请求已被成功接收,继续处理 |
| 2XX | 成功 | 表示请求已被成功接收,理解,接受 |
| 3XX | 重定向 | 要完成请求必须进行更进一步的处理 |
| 4XX | 客户端错误 | 请求有语法错误或请求无法实现 |
| 5XX | 服务器端错误 | 服务器未能实现合法的请求 |
常用状态码详解:
成功类
200 OK:请求成功
201 Created:资源已创建
204 No Content:成功但无内容返回
重定向类
301 Moved Permanently:永久重定向
302 Found:临时重定向
304 Not Modified:使用缓存,无需重新下载
客户端错误
400 Bad Request:请求参数错误
401 Unauthorized:未认证
403 Forbidden:权限不足
404 Not Found:资源不存在
429 Too Many Requests:请求太频繁
服务器错误
500 Internal Server Error:通用错误
502 Bad Gateway:网关错误(上游服务异常)
503 Service Unavailable:服务器过载或维护
504 Gateway Timeout:上游超时
HTTP连接管理
HTTP协议是无状态的面向连接的协议
HTTP/1.0中:默认短连接
也就是说对于发送过的请求和响应都不做持久化处理,每一次都认为是新的请求或响应,每个请求都要重新建立TCP。
但是后来这样就变得很不方便
HTTP/1.1及以后: 默认长连接(开启了 Keep-Alive)
一个TCP可复用多次,提升性能,与用户身份无关
简单地说,当一个网页打开完成后,客户端和服务器之间用于传输 HTTP 数据的 TCP 连接不会关闭,如果客户端再次访问这个服务器上的网页,会继续使用这一条已经建立的 TCP 连接。
Keep-Alive 不会永久保持连接,它有一个保持时间,可以在不同服务器软件(如 Apache)中设置这个时间。
HTTP管理用户状态
两种方式:Cookie + Session / Token → 用于"用户身份与状态管理"
mathematica
┌──────────┐
│ Cookie │ ← 浏览器存储小数据
└────┬─────┘
│
├── 保存 session_id → 服务器取 Session(状态在服务器)
│
└── 保存 Token(JWT) → 服务器校验签名(状态在客户端)
Cookie:浏览器保留小数据并自动发送给服务器
Cookie 是存储在浏览器的小数据,例如:
- session_id(用于服务器识别用户)
- 登录状态
- 业务信息
每次对同域名请求时,浏览器都会自动带上 Cookie。
Cookie 是 Session、Token 的传输载体之一,不是身份验证本身。
Session:服务器端存储的用户状态
Session 的核心:
- 数据存服务器
- 浏览器只保存一个 session_id(通常存在 Cookie 中)
- 服务端根据 session_id 找用户数据
典型流程:
浏览器访问:
Cookie: session_id=abc123
服务端查 session 表:
session["abc123"] = {user_id: 1, login:true}
Token(如 JWT):客户端携带完整凭证
Token 的定位:
- 数据存在客户端
- 服务端不存用户状态(无状态认证)
- 每次请求需要带上 Token(Authorization header)
如:
Authorization: Bearer eyJhbGciOi...
HTTP连接管理和用户状态管理的协同使用
-
使用 TCP + keep-alive 建立连接(保持连接不断开)
-
发 HTTP 请求:"POST /login"
-
服务器验证用户名密码
-
登录成功后:
- Session 方式 :返回
Set-Cookie: session_id=xxx - JWT Token 方式 :返回
authorization token
- Session 方式 :返回
-
浏览器保留 Cookie / Token
-
下一次请求
mathematica┌───────────────────────────┐ │是否复用 TCP 连接 (keep-alive) ------ 性能优化,与身份无关 └───────────────┬───────────────┘ ↓ 浏览器自动带上: Cookie: session_id=xxx 或 Authorization: Bearer token ↓ 服务器识别用户身份: Session:用 session_id 查服务器存储 或Token:验证 Token 签名,直接解析身份
可以看到:
- keep-alive 只是优化连接,不管你是谁
- Cookie/Session/Token 管理你是谁
其它协议与HTTP的关系
| 
|
| ------------------------------------------------------------ |
HTTP的缓存
目的:
提升性能,减少服务器压力,提升用户体验。
HTTP 缓存分为两类:
① 强制缓存(强缓存 / 本地缓存)
浏览器直接使用本地缓存,不与服务端通信、请求都不会发出去。
依赖两个Header : Cache-Control、Expires(已过时)
bash
Cache-Control: max-age=3600, public
② 协商缓存(弱缓存 / 条件缓存)
浏览器会向服务器发送请求,但带上缓存验证信息:
If-Modified-SinceIf-None-Match
服务器判断是否能用缓存:
- 可以 → 返回 304 Not Modified,浏览器继续用本地缓存
- 不可以 → 返回 200 + 新资源
依赖三组Header:
If-Modified-Since + Last-Modified(按时间判断)
If-None-Match + ETag(推荐,基于内容)
Cache-Control + ETag
bash
# If-Modified-Since + Last-Modified(按时间判断)
# 服务器返回资源时带:
Last-Modified: Tue, 10 Jan 2025 10:00:00 GMT
# 下次请求If-Modified-Since: Tue, 10 Jan 2025 10:00:00 GMT浏览器带:
If-Modified-Since: Tue, 10 Jan 2025 10:00:00 GMT
服务器判断:
文件没有变化 → 返回 304
变化了 → 返回 200 + 新内容
缺点:
时间精度是秒,1 秒内多次修改无法识别
内容没变但时间变了,也会导致重复下载
# If-None-Match + ETag(推荐,基于内容)
# 服务器给资源计算一个 hash:
ETag: "abc123"
# 下次请求浏览器带:
If-None-Match: "abc123"
服务器判断:
hash 一致 → 304
不一致 → 200 + 新内容
优点:
精度高,不受时间影响
内容不变 hash 不变,最准确
# Cache-Control + ETag
Cache-Control: no-cache # 不使用强缓存
ETag: "abc123" # 决定资源是否变化
HTTP 缓存整体决策流程图
mathematica
┌──────────────┐
│ 强缓存可用? │ ← Cache-Control: max-age
└───────┬──────┘
│是
▼
浏览器直接使用缓存(不发请求)
│否
▼
┌──────────────┐
│ 协商缓存可用? │ ← If-None-Match / If-Modified-Since
└───────┬──────┘
│是
▼
返回 304,用本地缓存
│否
▼
请求服务器 → 返回 200 新资源
HTTPS
HTTP 本身是不安全的:
- 明文传输
- 可能被窃听(抓包能看到内容)
- 可能被篡改(中间人攻击 MITM)
- 可能被伪装(假服务器)
为了解决这些问题,HTTP 加上了 TLS 加密层,于是变成 HTTPS。
HTTPS 解决三件事
- 加密(数据不会被窃听)
- 完整性(不会被篡改)
- 认证(确认服务器是真的)
使用两种加密方式协作
- 非对称加密(RSA/ECDHE):安全地交换密钥
- 对称加密(AES):加密真正的数据
数字证书(CA)
服务器通过证书提供公钥、 浏览器用 CA 链验证证书是否可信、 防止假网站冒充
握手流程
- 客户端发起:支持的加密算法 + 随机数
- 服务器回证书 + 随机数
- 客户端生成 pre-master key,用公钥加密发给服务器
- 双方生成同一个对称密钥
- 之后所有 HTTP 都用这个对称密钥加密
总结:HTTPS 用证书验证服务器,用非对称加密交换密钥,再用对称加密安全传输 HTTP 数据。