目录
[1.3、Server-Sent Events (SSE) 与 WebSocket](#1.3、Server-Sent Events (SSE) 与 WebSocket)
[2、长连接 vs 短连接](#2、长连接 vs 短连接)
[3.1、HTTP/1.1 中的机制](#3.1、HTTP/1.1 中的机制)
前沿
自 HTTP/1.0 诞生以来,"连接复用"始终是 Web 性能优化的核心命题。从 Connection:keep-alive 到 HTTP/2 多路复用,再到 HTTP/3 的 QUIC 连接迁移,HTTP 连接模型正经历一场静默革命。
如下所示:

历史回溯:为什么需要"长连接"?
1 短连接的代价(HTTP/1.0 时代)
-
每个请求 = 1 次 TCP 三次握手 + 1 次 TLS 握手(HTTPS)+ 1 次四次挥手
-
延迟开销:在 100ms RTT 网络中,仅握手就耗时 300ms+
-
资源消耗:服务端每秒新建数千连接,文件描述符迅速耗尽
如下所示:

数据:加载一个含 50 个资源的网页,HTTP/1.0 需 50 次 TCP 连接!
2 长连接的诞生(HTTP/1.1)
-
默认行为:Connection:keep-alive(无需显式声明)
-
核心价值 :单 TCP 连接复用多次请求,减少握手开销 90%+
-
局限 :队头阻塞(Head-of-Line Blocking) ------ 后续请求必须等前一个响应返回
当 HTTP 响应头中包含 Connection**
: close时,这个连接是「短连接」。**
1、现实背景
现代架构中的连接策略:不止于"长 or 短"。
1.1、微服务时代
Client-Side Pooling
问题:
服务 A → 服务 B 的高频调用,若每次新建连接,B 会 OOM。
解法:
客户端维护连接池(如 OkHttp、Apache HttpClient)。
代码如下所示:
java
// OkHttp 连接池配置
new OkHttpClient.Builder()
.connectionPool(new ConnectionPool(20, 5, TimeUnit.MINUTES))
.build();
本质 :应用层长连接,绕过 HTTP 协议限制。
1.2、服务网格
(Sidecar 模式)
Istio / Envoy 在 Pod 内注入 Sidecar
出站连接:Sidecar 维护到目标服务的长连接池
入站连接:Sidecar 接收短连接,转发到本地 App(App 只需处理短连接)
优势:业务代码无感知,连接策略由基础设施统一治理
1.3、Server-Sent Events (SSE) 与 WebSocket
超长连接
-
SSE:单向长连接(服务端 → 客户端),用于实时通知
-
WebSocket:全双工长连接,用于聊天、游戏
-
特点 :连接存活数小时甚至数天,彻底脱离 HTTP 请求-响应模型
2、长连接 vs 短连接
2.1、架构图
如下所示:

2.2、区别
如下所示:
| 类型 | 行为 | 特点 |
|---|---|---|
| 短连接(Short-lived Connection) | 每次 HTTP 请求/响应完成后,立即关闭 TCP 连接 | - 每次请求都要经历 TCP 三次握手 + 四次挥手 - 开销大,适合低频请求 |
| 长连接(Persistent Connection) | 一次 TCP 连接上可发送多个 HTTP 请求/响应,用完不立即关 | - 减少握手开销 - 需要 Connection: keep-alive - 适合高频请求 |
2.3、生效规则
长连接与短连接的最终生效:
是 前端请求声明、后端响应确认、协议默认规则 三者共同作用的结果,并非单一由前端或后端决定。
具体责任划分和优先级如下:
1、核心规则:HTTP 协议的 "双向协商" 机制
HTTP 是 "请求 - 响应" 模型,连接类型的选择遵循 "前端发起声明,后端决定是否同意" 的协商逻辑,核心依赖 Connection 请求头和响应头:
前端(客户端):
发起请求时,通过 Connection 头声明希望使用的连接类型(长连接 / 短连接);
后端(服务器):
收到请求后,通过自身配置和业务需求,在响应头的 Connection 中返回 "同意 / 拒绝" 的结果;
最终生效:以 后端响应头的 Connection 为准(后端有权否决前端的声明)。
2、分角色责任:前端 "声明",后端 "决策",协议 "兜底"
①. 前端(客户端):负责 "发起声明"
前端的核心作用是 在请求头中携带 Connection 字段,声明期望的连接类型。
具体行为分场景:
手动设置:前端可通过代码主动声明连接类型(如 AJAX、Fetch 请求):
TypeScript
// Fetch 请求手动声明长连接
fetch('/api/data', {
method: 'GET',
headers: {
'Connection': 'keep-alive' // 前端声明:希望用长连接
}
});
// 手动声明短连接
fetch('/api/data', {
headers: { 'Connection': 'close' } // 前端声明:希望用短连接
});
默认行为:
若前端不手动设置 Connection 头,由 浏览器 / HTTP 客户端(如 Axios、Postman)按协议版本默认填充:
HTTP/1.1 及以上(主流):
默认填充 Connection: keep-alive(即默认请求长连接);
HTTP/1.0(老旧场景):
默认不填 Connection 头(等效于 Connection: close,即默认请求短连接)。
②. 后端(服务器):负责 "最终决策"
后端的核心作用是 根据自身配置和业务需求,决定是否同意前端的连接声明,并通过响应头的 Connection 字段返回结果,优先级最高:
后端同意前端声明:
1.若前端请求 Connection: keep-alive,且后端开启长连接配置,则响应头返回 Connection: keep-alive,最终生效长连接;
2.若前端请求 Connection: close,后端通常会响应 Connection: close,最终生效短连接。
后端否决前端声明:
若前端请求 Connection: keep-alive:
但后端配置强制关闭长连接(如 Nginx 设 keepalive_disable all),则响应头返回 Connection: close,最终生效短连接;
若前端请求 Connection: close:
但后端因特殊需求(如高频请求优化)强制返回 Connection: keep-alive,则最终生效长连接(极少场景,不符合 "客户端意愿")。
示例:后端 Nginx 长连接配置(决定是否支持长连接):
Lua
http {
keepalive_timeout 60s; # 长连接超时时间:60秒无新请求则关闭连接
keepalive_requests 100; # 一个长连接最多处理100个请求(避免连接长期占用)
}
③. 协议(HTTP 版本):负责 "兜底默认值"
当前端未手动设置 Connection 头、后端也未主动返回 Connection 头时,由 HTTP 协议版本的默认规则兜底:
HTTP/1.1 及以上:默认生效长连接 (等效于后端响应 Connection: keep-alive);
**HTTP/1.0 及以下:默认生效短连接(**等效于后端响应 Connection: close)。
这也是为什么现代 Web 场景(均基于 HTTP/1.1+)几乎默认都是长连接。
3、特殊场景:HTTP/2+ 无需手动协商,默认长连接
HTTP/2(及 HTTP/3)彻底简化了连接协商逻辑:
废除 Connection 头:
HTTP/2 明确规定忽略 Connection 头,无论前后端是否携带该头,均不影响连接类型;
强制默认长连接:
HTTP/2 基于 "多路复用"(一个 TCP 连接并行处理多个请求),天生是长连接,无需协商;
后端配置控制超时:
此时,"长连接" 是协议层面的强制默认,前后端无需手动设置,仅需后端配置超时参数即可。
3、Connection:close
3.1、HTTP/1.1 中的机制
在 HTTP/1.1 中:
-
默认行为是长连接(persistent connection)
-
但任何一方都可以通过 Connection:close终止连接
🤝 协商规则:
| 客户端请求 | 服务端响应 | 最终行为 |
|---|---|---|
| keep-alive | keep-alive | ✅ 长连接(复用) |
| keep-alive | close | ❌ 短连接(用完就关) |
| close | keep-alive | ❌ 短连接(用完就关) |
| close | close | ❌ 短连接 |
close具有"否决权" ------ 只要任一方发 close,连接就不会复用。
为什么服务端会返回 Connection:close?
3.2、触发条件
即使你请求的是 keep-alive,服务端仍可能出于以下原因主动关闭连接:
- 服务端配置强制短连接
- 某些 Web 服务器(如 Nginx、Apache)可配置:
bash
# Nginx 示例:对特定路径禁用 keep-alive
location /api/ {
keepalive_timeout 0; # 立即关闭
}
- 服务端资源压力大
- 高并发时,服务端主动关闭连接以释放文件描述符,避免 Too many open files
- 响应内容特殊
-
返回 Transfer-Encoding:chunked 且无法确定长度时
-
返回错误(如 5xx)时,部分框架会关闭连接
- 应用层逻辑控制
- 你的后端代码显式设置了:
java
// Spring Boot 示例
response.setHeader("Connection", "close");
- 代理/网关行为
- API 网关(如 Kong、APISIX)、负载均衡器(如 SLB)可能统一关闭连接以简化管理
3.2、作用
它明确告诉对方:"本次通信结束后,请关闭 TCP 连接。"
-
无论是客户端发给服务端,还是服务端返回给客户端
-
只要有一方发送 Connection:close,该连接就会在当前事务结束后关闭
示例流程如下:
bash
# 客户端请求
GET /index.html HTTP/1.1
Host: example.com
Connection: close ← 告诉服务器:用完就关
# 服务器响应
HTTP/1.1 200 OK
Content-Length: 1234
Connection: close ← 告诉客户端:我发完就关
[传输 HTML 内容]
→ TCP 连接关闭
即使你之前用的是长连接,只要某次通信中出现Connection:close,这次用完就断。
4、keep-alive
4.1、介绍
请求头(Request Header)是 Connection:keep-alive**,但响应头(Response Header)是**Connection:close ------ 是完全正常且常见的。
HTTP 连接是否复用,由「双方协商」决定,但只要有一方明确要求
close,连接就会在本次通信后关闭。
4.2、连接规则
如下所示:
| Header | 连接行为 | 是否长连接 |
|---|---|---|
| Connection:keep-alive | 保持连接,后续可复用 | ✅ 是 |
| Connection:close | 用完立即关闭 | ❌ 否(短连接) |
| 无Connection头(HTTP/1.0) | 默认关闭 | ❌ 短连接 |
| 无Connection头(HTTP/1.1) | 默认保持(等价于 keep-alive) | ✅ 长连接 |
⚠️ 注意:HTTP/1.1 默认是长连接,除非显式指定 close。
5、最佳实践
5.1、实际应用
误解 1:"用了 TCP 就是长连接"
-
错! TCP 只是传输层协议,HTTP 应用层决定是否复用
-
一个 TCP 连接可以只传一次 HTTP(短连接),也可以传多次(长连接)
误解 2:"Connection: close 是长连接的一种状态"
-
错! 它是主动终结长连接的信号
-
一旦出现,本次通信后连接必断
正确认知:
Connection**
:** close**= 明确要求使用短连接行为**
如何设计连接策略:

5.2、实际影响
场景 1:客户端想节省资源
bash
# 主动关闭,避免占用连接池
GET /api/health HTTP/1.1
Host: backend
Connection: close
场景 2:服务端强制断连
-
服务器负载高时,返回 Connection
:close 让客户端不要复用 -
节省服务端连接资源
场景 3:调试时避免连接复用
- 用 curl -H "Connection:close" http://...确保每次新建连接
6、未来走向
6.1、协议革新
HTTP/2 与 HTTP/3 如何"消灭"长/短连接之争?
1 HTTP/2:多路复用(Multiplexing)
-
核心突破:单 TCP 连接上并行传输多个请求/响应
-
效果:
-
彻底解决 HTTP/1.x 队头阻塞
-
不再需要多个 TCP 连接(浏览器默认只开 1 个连接/域名)
-
-
连接语义变化:
"长连接"不再是优化手段,而是唯一合理模式
2 HTTP/3:QUIC 协议重定义连接
-
底层协议:基于 UDP 的 QUIC(而非 TCP)
-
革命性特性:
-
连接迁移(Connection Migration):IP 变更(如 WiFi → 4G)不中断连接
-
0-RTT 握手:会话恢复时,首个请求无握手延迟
-
内置加密:TLS 1.3 与传输层融合
-
-
影响:
"连接"概念弱化 ------ QUIC 流(Stream)成为新基本单位,
应用更关注"流"的可靠性,而非"TCP 连接"的存续。
6.2、前沿趋势
无连接(Connectionless)Web 正在到来
1 Serverless 与短连接复兴
-
AWS Lambda / 阿里云 FC:函数实例冷启动后处理单次请求
-
行为:天然使用短连接(处理完即销毁)
-
优化 :通过 Provisioned Concurrency 预热实例,模拟"长连接"效果
2 CDN 边缘计算:连接终结于边缘
-
用户 → CDN 节点:短连接(TLS 1.3 0-RTT 降低开销)
-
CDN 节点 → 源站:长连接池(由 CDN 厂商维护)
-
结果:终端用户无感知,源站压力大幅降低
3 WebTransport:下一代双向通信
-
基于 HTTP/3 QUIC 的 API
-
支持:
-
可靠流(Reliable Streams)
-
不可靠数据报(Datagrams)
-
-
愿景 :统一 WebSocket、WebRTC、HTTP,终结"连接类型选择"难题
总结
从 HTTP/1.0 的"连接即成本",到 HTTP/1.1 的"长连接优化",再到 HTTP/3 的"连接无感",我们正见证一个趋势:
连接(Connection)正在从"开发者关注的资源"退化为"基础设施透明处理的细节"。
未来的 Web 开发者,将不再纠结于"长 or 短",而是聚焦于:
- 数据流(Stream)的可靠性
- 请求的优先级调度
- 网络条件的自适应
这,才是 HTTP 连接演进的真正前沿。
参考文章