一、HTTP 单连接与多连接
1. 单连接模式 (HTTP/1.1 默认)
特点:
-
同一域名下所有请求共享一个TCP连接
-
请求必须按顺序发送和接收(队头阻塞问题)
-
通过
Connection: keep-alive
保持长连接
示例:
客户端: GET /resource1
服务器: 响应1
客户端: GET /resource2 (必须等待响应1完成)
服务器: 响应2
2. 多连接模式
HTTP/1.1 解决方案:
-
浏览器为同一域名打开多个TCP连接(通常6-8个)
-
并行发送请求,缓解队头阻塞
HTTP/2 多路复用:
-
单一TCP连接上并行交错传输多个请求/响应
-
二进制分帧层解决队头阻塞
-
请求/响应可以交错,不受顺序限制
对比表:
特性 | HTTP/1.1 单连接 | HTTP/1.1 多连接 | HTTP/2 |
---|---|---|---|
连接数 | 1 | 6-8 | 1 |
队头阻塞 | 严重 | 部分缓解 | 完全解决 |
资源开销 | 低 | 高 | 低 |
服务器压力 | 低 | 高 | 低 |
二、HTTP 预检请求 (Preflight Request)
1. 什么是预检请求
预检请求是浏览器在发送某些跨域请求前,先使用 OPTIONS
方法发起一个预检请求,以确定实际请求是否安全的机制。
2. 触发预检的条件
当请求满足以下任一条件时,浏览器会发送预检请求:
-
使用特定HTTP方法:
- 非简单方法:PUT、DELETE、CONNECT、OPTIONS、TRACE、PATCH
-
设置了非简单头部字段:
-
非简单头部:除以下之外的头部
-
Accept
-
Accept-Language
-
Content-Language
-
Content-Type(仅限特定值)
-
DPR
-
Downlink
-
Save-Data
-
Viewport-Width
-
Width
-
-
-
Content-Type 非简单值:
- 非以下类型:
text/plain
、multipart/form-data
、application/x-www-form-urlencoded
- 非以下类型:
3. 预检请求示例
客户端发送OPTIONS预检:
OPTIONS /resource HTTP/1.1
Host: api.example.com
Origin: https://yourdomain.com
Access-Control-Request-Method: DELETE
Access-Control-Request-Headers: X-Custom-Header
服务器响应:
HTTP/1.1 204 No Content
Access-Control-Allow-Origin: https://yourdomain.com
Access-Control-Allow-Methods: GET, POST, DELETE
Access-Control-Allow-Headers: X-Custom-Header
Access-Control-Max-Age: 86400
4. 预检请求工作流程
-
浏览器检测到需要预检的跨域请求
-
先发送OPTIONS请求进行预检
-
服务器响应是否允许实际请求
-
如果允许,浏览器发送实际请求
-
服务器响应实际请求
5. 避免预检的方法
-
使用简单请求:
-
GET/HEAD/POST方法
-
仅使用简单头部
-
Content-Type为简单类型
-
-
利用缓存:
-
设置
Access-Control-Max-Age
头部Access-Control-Max-Age: 86400 // 缓存1天
-
-
后端配置CORS:
-
正确配置
Access-Control-Allow-*
头部 -
处理OPTIONS请求
-
三、实际开发中的场景示例
1. 触发预检的请求
javascript
// 自定义头部触发预检
fetch('https://api.example.com/data', {
method: 'PUT',
headers: {
'Content-Type': 'application/json',
'X-Auth-Token': 'abc123' // 自定义头部
},
body: JSON.stringify({ key: 'value' })
});
2. 不触发预检的简单请求
javascript
// 简单GET请求
fetch('https://api.example.com/data');
// 简单POST表单请求
fetch('https://api.example.com/submit', {
method: 'POST',
headers: {
'Content-Type': 'application/x-www-form-urlencoded',
},
body: 'key1=value1&key2=value2'
});
3. Node.js 服务端CORS配置示例
javascript
// Express 中间件
app.use((req, res, next) => {
// 允许的源
res.setHeader('Access-Control-Allow-Origin', 'https://yourdomain.com');
// 允许的方法
res.setHeader('Access-Control-Allow-Methods', 'GET, POST, OPTIONS, PUT, DELETE');
// 允许的头部
res.setHeader('Access-Control-Allow-Headers', 'X-Requested-With, Content-Type, Authorization');
// 预检请求缓存时间
res.setHeader('Access-Control-Max-Age', '86400');
// 处理预检请求
if (req.method === 'OPTIONS') {
return res.sendStatus(200);
}
next();
});
理解这些机制有助于优化Web应用性能(通过合理使用连接)和正确处理跨域请求(通过理解预检机制)。