HTTP 长连接 vs 短连接:从 TCP 优化到 QUIC 时代的演进

目录

1、现实背景

1.1、微服务时代

1.2、服务网格

[1.3、Server-Sent Events (SSE) 与 WebSocket](#1.3、Server-Sent Events (SSE) 与 WebSocket)

[2、长连接 vs 短连接](#2、长连接 vs 短连接)

2.1、架构图

2.2、区别

2.3、生效规则

3、Connection:close

[3.1、HTTP/1.1 中的机制](#3.1、HTTP/1.1 中的机制)

3.2、触发条件

3.2、作用

4、keep-alive

4.1、介绍

4.2、连接规则

5、最佳实践

5.1、实际应用

5.2、实际影响

6、未来走向

6.1、协议革新

6.2、前沿趋势


前沿

自 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,服务端仍可能出于以下原因主动关闭连接

  1. 服务端配置强制短连接
  • 某些 Web 服务器(如 Nginx、Apache)可配置:
bash 复制代码
# Nginx 示例:对特定路径禁用 keep-alive
location /api/ {
    keepalive_timeout 0;  # 立即关闭
}
  1. 服务端资源压力大
  • 高并发时,服务端主动关闭连接以释放文件描述符,避免 Too many open files
  1. 响应内容特殊
  • 返回 Transfer-Encoding:chunked 且无法确定长度时

  • 返回错误(如 5xx)时,部分框架会关闭连接

  1. 应用层逻辑控制
  • 你的后端代码显式设置了:
java 复制代码
// Spring Boot 示例
response.setHeader("Connection", "close");
  1. 代理/网关行为
  • 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 连接演进的真正前沿。


参考文章

1、HTTP之原理,长短连接,响应码,八种方法,与RPC区别

相关推荐
_F_y2 小时前
传输层协议:TCP
网络·网络协议·tcp/ip
鲨莎分不晴2 小时前
告别TCP?HTTP/3与QUIC协议如何重塑下一代Web体验
网络协议·tcp/ip·http
有趣灵魂2 小时前
Java-根据HTTP链接读取文件转换为base64
java·开发语言·http
bkspiderx2 小时前
用Nginx解决HTTP跨域问题:两种实用方案详解
nginx·http·跨域·http跨域
路由侠内网穿透.2 小时前
本地部署远程服务管理软件 IntelliSSH 并实现外部访问
运维·服务器·网络·网络协议
钟智强2 小时前
红队实战复盘:如何运用【火尖枪】高效突破复杂登录防线
服务器·安全·web安全·http·go·php·bruteforce
福尔摩斯张2 小时前
嵌入式硬件篇:常见单片机型号深度解析与技术选型指南
网络·数据库·stm32·单片机·网络协议·tcp/ip·mongodb
Dovis(誓平步青云)3 小时前
《 传输层协议精解:TCP的三次握手与UDP的无连接特性全解析》
网络协议·tcp/ip·udp
未来之窗软件服务5 小时前
幽冥大陆(六十八) PHP8.x SSL 文字加密—东方仙盟古法结界
网络·网络协议·ssl·仙盟创梦ide·东方仙盟·文字加密