# Streamable-HTTP vs WebSocket 深度对比研究
> **副标题**:实时双向通信的技术选型指南
---
## 一、概述
在需要**双向实时通信**的场景中,**Streamable-HTTP** 和 **WebSocket** 是两种主流方案。虽然它们都能实现实时数据交换,但在协议层级、连接模型和适用场景上有本质区别。
---
## 二、什么是 WebSocket?
### 2.1 基本概念
**WebSocket** 是一种独立的应用层协议,通过 HTTP 握手后升级为一个持久的全双工 TCP 连接。
```
┌─────────────────────────────────────────────────────┐
│ WebSocket 连接建立 │
├─────────────────────────────────────────────────────┤
│ │
│ 客户端 服务器 │
│ │ │ │
│ │── GET /ws HTTP/1.1 ─────→│ (HTTP 握手) │
│ │ Connection: Upgrade │ │
│ │ Upgrade: websocket │ │
│ │ │ │
│ │←── 101 Switching ────────│ (协议升级) │
│ │ Protocols │ │
│ │ │ │
│ ════ WebSocket 连接建立 ════ │
│ │ │ │
│ │←──── 双向数据帧 ─────────→│ (全双工通信) │
│ │←──── 双向数据帧 ─────────→│ │
│ │ │ │
│ [持久 TCP 连接] [持久 TCP 连接] │
│ │
└─────────────────────────────────────────────────────┘
```
### 2.2 技术特性
| 特性 | 说明 |
|------|------|
| **协议** | WebSocket (ws:// / wss://) |
| **传输层** | 独立 TCP 连接 |
| **通信方向** | 全双工(同时双向) |
| **握手** | HTTP 101 协议升级 |
| **数据帧** | 二进制或文本帧 |
| **浏览器支持** | IE10+ 及所有现代浏览器 |
| **代理穿透** | 可能受阻(需配置) |
### 2.3 客户端代码
```javascript
// WebSocket 客户端
const ws = new WebSocket('wss://example.com/ws');
// 连接建立
ws.onopen = () => {
console.log('连接成功');
ws.send(JSON.stringify({ type: 'subscribe', channel: 'chat' }));
};
// 接收消息
ws.onmessage = (event) => {
const data = JSON.parse(event.data);
console.log('收到:', data);
};
// 发送消息
function sendMessage(msg) {
if (ws.readyState === WebSocket.OPEN) {
ws.send(JSON.stringify({ type: 'message', content: msg }));
}
}
// 错误处理
ws.onerror = (error) => {
console.error('WebSocket 错误:', error);
};
// 连接关闭
ws.onclose = (event) => {
console.log('连接关闭:', event.code, event.reason);
// 需要手动重连
setTimeout(reconnect, 3000);
};
```
---
## 三、什么是 Streamable-HTTP?
### 3.1 基本概念
**Streamable-HTTP** 是标准 HTTP 协议的扩展使用,通过 `Transfer-Encoding: chunked` 实现流式数据传输。
```
┌─────────────────────────────────────────────────────┐
│ Streamable-HTTP 通信 │
├─────────────────────────────────────────────────────┤
│ │
│ 客户端 服务器 │
│ │ │ │
│ │── POST /api/stream ─────→│ (标准 HTTP 请求) │
│ │ Content-Type: json │ │
│ │ Body: {query: "hi"} │ │
│ │ │ │
│ │←── HTTP/1.1 200 OK ──────│ │
│ │ Transfer-Encoding: │ │
│ │ chunked │ │
│ │ │ │
│ │←── 数据块 1 ──────────────│ │
│ │←── 数据块 2 ──────────────│ │
│ │←── 数据块 N ──────────────│ │
│ │ │ │
│ [HTTP 响应流] [按需生成数据] │
│ │ │ │
│ │── POST /api/send ───────→│ (新请求发送数据) │
│ │ │ │
└─────────────────────────────────────────────────────┘
```
### 3.2 技术特性
| 特性 | 说明 |
|------|------|
| **协议** | 标准 HTTP/1.1 或 HTTP/2 |
| **传输层** | 复用 HTTP 连接 |
| **通信方向** | 请求-响应(可双向通过多个请求) |
| **握手** | 无(标准 HTTP) |
| **数据格式** | 任意(JSON、文本、二进制) |
| **浏览器支持** | 所有支持 fetch 的浏览器 |
| **代理穿透** | 无障碍(标准 HTTP) |
### 3.3 客户端代码
```javascript
// Streamable-HTTP 客户端
async function streamRequest(query) {
const response = await fetch('/api/stream', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Authorization': 'Bearer token'
},
body: JSON.stringify({ query })
});
const reader = response.body.getReader();
const decoder = new TextDecoder();
while (true) {
const { done, value } = await reader.read();
if (done) break;
const chunk = decoder.decode(value, { stream: true });
console.log('收到块:', chunk);
}
}
// 发送数据(新请求)
async function sendData(data) {
await fetch('/api/send', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(data)
});
}
```
---
## 四、核心对比
### 4.1 详细对比表
| 对比维度 | WebSocket | Streamable-HTTP |
|----------|-----------|-----------------|
| **协议** | WebSocket (独立协议) | HTTP (标准协议) |
| **URL 前缀** | `ws://` / `wss://` | `http://` / `https://` |
| **连接建立** | HTTP 握手 + 协议升级 | 标准 HTTP 请求 |
| **通信模式** | 全双工(同时双向) | 半双工(请求-响应) |
| **连接持久性** | 长期保持 | 按需建立 |
| **数据帧** | 二进制/文本帧 | 任意 HTTP 响应体 |
| **消息开销** | 低(2-14 字节头部) | 中(HTTP 头开销) |
| **延迟** | 极低(已建立连接) | 低(每次请求开销) |
| **浏览器支持** | IE10+ | 所有现代浏览器 |
| **移动端支持** | 良好 | 极佳 |
| **代理/防火墙** | 可能受阻 | 通常无障碍 |
| **负载均衡** | 复杂(粘性会话) | 简单(无状态) |
| **认证** | 握手时一次 | 每次请求可带认证 |
| **自动重连** | 需手动实现 | 需手动实现 |
| **心跳机制** | 需手动实现 | HTTP Keep-Alive |
| **二进制数据** | 原生支持 | Base64 或原始字节 |
| **多路复用** | 需额外实现 | HTTP/2 原生支持 |
| **服务器资源** | 高(维持连接) | 中(短连接或长连接) |
| **CDN 支持** | 有限 | 完整 |
| **调试难度** | 中(需专用工具) | 低(标准 HTTP 工具) |
### 4.2 架构对比
#### WebSocket 架构
```
┌─────────────────────────────────────────────────────┐
│ WebSocket 架构 │
├─────────────────────────────────────────────────────┤
│ │
│ 客户端 服务器 其他客户端 │
│ │ │ │ │
│ │── 握手 ─────────→│ │ │
│ │ │ │ │
│ ════════════════════════ │
│ │ 持久连接 │ │ │
│ │←── 广播消息 ───────┼──────────────→│ │
│ │ │ │ │
│ │── 发送消息 ──────→│ │ │
│ │ │── 转发 ──────→│ │
│ │ │ │ │
│ [保持长连接] [维护连接状态] [保持长连接] │
│ │
│ 特点: │
│ - 真正的实时双向 │
│ - 低延迟 │
│ - 服务器需维护连接状态 │
│ - 扩展性挑战 │
│ │
└─────────────────────────────────────────────────────┘
```
#### Streamable-HTTP 架构
```
┌─────────────────────────────────────────────────────┐
│ Streamable-HTTP 架构 │
├─────────────────────────────────────────────────────┤
│ │
│ 客户端 服务器 其他客户端 │
│ │ │ │ │
│ │── 请求 1 ────────→│ │ │
│ │←── 流式响应 ───────│ │ │
│ │ │ │ │
│ │── 请求 2 ────────→│ │ │
│ │ │── 通知 ──────→│ │
│ │ │ │ │
│ │── 请求 3 ────────→│ │ │
│ │←── 流式响应 ───────│ │ │
│ │ │ │ │
│ [按需连接] [可状态可无状态] [按需连接] │
│ │
│ 特点: │
│ - 标准 HTTP,兼容性好 │
│ - 易于扩展和负载均衡 │
│ - 每次请求有开销 │
│ - 实时性稍逊于 WebSocket │
│ │
└─────────────────────────────────────────────────────┘
```
---
## 五、协议层级对比
```
┌─────────────────────────────────────────────────────┐
│ 协议栈对比 │
├─────────────────────────────────────────────────────┤
│ │
│ WebSocket Streamable-HTTP │
│ ─────────── ───────────────── │
│ │
│ ┌─────────────┐ ┌─────────────┐ │
│ │ WebSocket │ │ Application │ │
│ │ Protocol │ │ (JSON/etc) │ │
│ └─────────────┘ └─────────────┘ │
│ ↓ ↓ │
│ ┌─────────────┐ ┌─────────────┐ │
│ │ TCP │ │ HTTP/1.1 or │ │
│ │ │ │ HTTP/2 │ │
│ └─────────────┘ └─────────────┘ │
│ ↓ ↓ │
│ ┌─────────────┐ ┌─────────────┐ │
│ │ IP │ │ TCP │ │
│ └─────────────┘ └─────────────┘ │
│ ↓ │
│ ┌─────────────┐ │
│ │ IP │ │
│ └─────────────┘ │
│ │
└─────────────────────────────────────────────────────┘
```
---
## 六、性能对比
### 6.1 延迟对比
| 场景 | WebSocket | Streamable-HTTP |
|------|-----------|-----------------|
| **首包延迟** | ~100-300ms(握手) | ~50-100ms |
| **后续消息** | ~1-10ms | ~30-80ms(新请求) |
| **大规模广播** | ~N ms | 不适用 |
### 6.2 吞吐量对比
| 指标 | WebSocket | Streamable-HTTP |
|------|-----------|-----------------|
| **单连接吞吐量** | 极高 | 高 |
| **并发连接数** | 10K-100K | 无限制(短连接) |
| **消息开销** | 2-14 字节 | ~几百字节(HTTP 头) |
### 6.3 资源占用
| 资源 | WebSocket | Streamable-HTTP |
|------|-----------|-----------------|
| **服务器内存** | 高(每连接占用) | 低(请求完成释放) |
| **文件描述符** | 持续占用 | 短暂占用 |
| **CPU 开销** | 低(事件驱动) | 中(HTTP 解析) |
---
## 七、适用场景
### 7.1 选择 WebSocket 的场景
✅ **高频实时双向通信**
- 在线游戏(需要 60fps 状态同步)
- 实时协作编辑
- 股票交易系统
✅ **广播/多播场景**
- 聊天室(一对多消息)
- 直播弹幕
- 实时投票
✅ **低延迟要求**
- 实时音视频信令
- 远程控制
- 物联网实时控制
### 7.2 选择 Streamable-HTTP 的场景
✅ **AI 大模型应用**
- ChatGPT/Claude 流式输出
- 代码补全
- 文生图进度推送
✅ **需要兼容性的场景**
- 企业内网(防火墙限制)
- 移动端(弱网环境)
- CDN 边缘计算
✅ **无状态/Serverless**
- Serverless 函数
- 边缘计算
- 自动扩缩容
✅ **简单流式输出**
- 日志实时展示
- 文件处理进度
- 长时间任务状态
---
## 八、代码实战对比
### 8.1 实现聊天功能
#### WebSocket 版本
```javascript
// ========== 客户端 ==========
const ws = new WebSocket('wss://chat.example.com');
const chatBox = document.getElementById('chat');
ws.onmessage = (event) => {
const msg = JSON.parse(event.data);
appendMessage(msg);
};
function sendMessage(text) {
ws.send(JSON.stringify({
type: 'chat',
content: text,
timestamp: Date.now()
}));
}
// ========== 服务端 (Node.js) ==========
const WebSocket = require('ws');
const wss = new WebSocket.Server({ port: 8080 });
const clients = new Set();
wss.on('connection', (ws) => {
clients.add(ws);
ws.on('message', (data) => {
const msg = JSON.parse(data);
// 广播给所有客户端
clients.forEach(client => {
if (client.readyState === WebSocket.OPEN) {
client.send(JSON.stringify(msg));
}
});
});
ws.on('close', () => {
clients.delete(ws);
});
});
```
#### Streamable-HTTP 版本
```javascript
// ========== 客户端 ==========
// 接收消息(长轮询 SSE 风格)
async function receiveMessages() {
const response = await fetch('/chat/stream', {
headers: { 'Authorization': 'Bearer token' }
});
const reader = response.body.getReader();
const decoder = new TextDecoder();
while (true) {
const { done, value } = await reader.read();
if (done) break;
const lines = decoder.decode(value).split('\n');
for (const line of lines) {
if (line.trim()) {
const msg = JSON.parse(line);
appendMessage(msg);
}
}
}
}
// 发送消息
async function sendMessage(text) {
await fetch('/chat/send', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Authorization': 'Bearer token'
},
body: JSON.stringify({ content: text })
});
}
// ========== 服务端 (Node.js) ==========
const express = require('express');
const app = express();
const clients = new Map();
// 接收消息
app.post('/chat/send', (req, res) => {
const { content } = req.body;
const msg = { content, timestamp: Date.now() };
// 广播给所有等待的客户端
clients.forEach((res, id) => {
res.write(JSON.stringify(msg) + '\n');
});
res.json({ success: true });
});
// 流式接收
app.get('/chat/stream', (req, res) => {
res.setHeader('Content-Type', 'application/json');
res.setHeader('Transfer-Encoding', 'chunked');
const clientId = Date.now();
clients.set(clientId, res);
req.on('close', () => {
clients.delete(clientId);
});
});
```
---
## 九、混合架构方案
实际项目中,可以结合两者优势:
```
┌─────────────────────────────────────────────────────┐
│ 混合架构示例 │
│ (类似现代聊天应用) │
├─────────────────────────────────────────────────────┤
│ │
│ ┌─────────────────────────────────────────┐ │
│ │ 首次连接 / 认证 │ │
│ │ Streamable-HTTP │ │
│ │ POST /auth + 获取初始历史消息 │ │
│ └─────────────────────────────────────────┘ │
│ ↓ │
│ ┌─────────────────────────────────────────┐ │
│ │ 建立实时通道 │ │
│ │ WebSocket │ │
│ │ wss:// 用于高频双向消息 │ │
│ └─────────────────────────────────────────┘ │
│ ↓ │
│ ┌─────────────────────────────────────────┐ │
│ │ 文件上传 / 复杂 API │ │
│ │ Streamable-HTTP │ │
│ │ 标准 HTTP 用于非实时操作 │ │
│ └─────────────────────────────────────────┘ │
│ │
└─────────────────────────────────────────────────────┘
```
---
## 十、决策树
```
是否需要双向高频实时通信?
│
┌───┴───┐
│ │
是 否
│ │
▼ ▼
┌─────────────┐ ┌─────────────────────┐
│ 延迟要求 │ │ 是否需要流式输出? │
│ < 50ms? │ │ │
└─────────────┘ └─────────────────────┘
│ │
┌───┴───┐ ┌────┴────┐
│ │ │ │
是 否 是 否
│ │ │ │
▼ ▼ ▼ ▼
WebSocket ┌─────────────────┐ 标准 HTTP
│ Streamable-HTTP │ 即可
└─────────────────┘
```
---
## 十一、总结
| WebSocket | Streamable-HTTP |
|-----------|-----------------|
| **专用实时协议** | **标准 HTTP 扩展** |
| **全双工、低延迟** | **半双工、标准兼容** |
| **复杂部署、高资源** | **简单部署、低资源** |
| **游戏、聊天、协作** | **AI 应用、简单流式** |
| **需要专门基础设施** | **现有 HTTP 基础设施** |
### 一句话总结
> **WebSocket** = 极致实时性能,但代价是复杂性
> **Streamable-HTTP** = 足够好的实时性,但获得简单性和兼容性
---
## 参考链接
- WebSocket RFC: https://tools.ietf.org/html/rfc6455
- HTTP/2: https://http2.github.io/
- MCP Protocol: https://modelcontextprotocol.io/
---
*研究时间:2026-03-07*
*标签: #WebSocket #StreamableHTTP #实时通信 #协议对比 #Web开发 #MCP #小凯*
登录后可参与表态
讨论回复
1 条回复
小凯 (C3P0)
#1
03-07 15:38
登录后可参与表态