**更新时间:** 2026-03-27
**阅读时间:** 约 12 分钟
**适用人群:** Web 开发者、后端工程师、架构师
---
WebSocket 和 HTTP 是 Web 开发中最常用的两种通信协议,但它们的设计目标和使用场景截然不同。本文将深入对比两者的核心差异,帮助你选择合适的协议。
---
HTTP vs WebSocket 架构对比
flowchart TB
subgraph HTTP["HTTP 请求-响应模式"]
H1[浏览器] -->|1. 请求| WS[Web服务器]
WS -->|2. 响应| H1
H1 -->|3. 新请求| WS
WS -->|4. 新响应| H1
end
subgraph WS["WebSocket 全双工模式"]
B2[浏览器] <-->|双向帧| S2[WebSocket服务器]
end
style HTTP fill:#f39c12,color:#fff
style WS fill:#27ae60,color:#fff
| 特性 | HTTP | WebSocket |
|------|------|-----------|
| 连接类型 | 无状态、短连接 | 有状态、长连接 |
| 通信方向 | 单向(客户端请求→服务器响应) | 双向(全双工通信) |
| 连接保持 | 每次请求后关闭(HTTP/1.1 可保持) | 连接持续保持,直到主动关闭 |
| 握手开销 | 每次请求都有完整 HTTP 头 | 仅握手一次,后续数据传输开销小 |
**HTTP(HyperText Transfer Protocol)**
**WebSocket**
---
WebSocket 完整握手机序图
sequenceDiagram
participant B as 浏览器
participant S as 服务器
Note over B,S: HTTP握手阶段
B->>S: GET /ws HTTP/1.1
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Key: dGhl...
S->>B: HTTP/1.1 101 Switching Protocols
Upgrade: websocket
Sec-WebSocket-Accept: s3pPL...
Note over B,S: WebSocket连接建立
loop 双向通信
B->>S: WebSocket 帧(文本/二进制)
S->>B: WebSocket 帧
end
Note over B,S: 全双工,低延迟
客户端 服务器
| |
|--- HTTP 请求 --------->|
| (Headers + Body) |
| |
|<-- HTTP 响应 ----------|
| (Status + Headers |
| + Body) |
| |
|--- 连接关闭 ---------->|
**HTTP/1.1 示例:**
GET /api/users HTTP/1.1
Host: example.com
Accept: application/json
HTTP/1.1 200 OK
Content-Type: application/json
Content-Length: 123
{"users": [...]}
客户端 服务器
| |
|--- HTTP 握手 --------->| (Upgrade: websocket)
| (Sec-WebSocket-Key) |
| |
|<-- 101 切换协议 -------| (Sec-WebSocket-Accept)
| |
|=== WebSocket 连接 ======| (持久连接)
| |
|<== 消息帧 =============>| (双向通信)
|<== 消息帧 =============>|
| |
|--- 关闭帧 ------------>| (可选)
**WebSocket 握手示例:**
客户端请求
GET /chat HTTP/1.1
Host: example.com
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==
Sec-WebSocket-Version: 13
服务器响应
HTTP/1.1 101 Switching Protocols
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Accept: s3pPLMBiTxaQ9kYGzzhZRbK+xOo=
---
WebSocket 生命周期状态机
stateDiagram-v2
[*] --> CONNECTING
CONNECTING --> OPEN : 服务器发送101
OPEN --> CLOSING : 任一方发起关闭
OPEN --> CLOSED : 连接失败/超时
CLOSING --> CLOSED : 收到关闭帧
CLOSED --> [*]
CONNECTING --> CLOSED : 连接失败
| 场景 | HTTP | WebSocket |
|------|------|-----------|
| 首次请求 | ~100-300ms(含 TCP 握手) | ~100-300ms(含 TCP+WS 握手) |
| 后续请求 | ~50-150ms(每次完整 HTTP) | ~5-20ms(仅数据帧) |
| 服务器推送 | 不支持(需轮询) | 支持(即时推送) |
**HTTP 开销:**
GET /api/data HTTP/1.1
Host: example.com
User-Agent: Mozilla/5.0
Accept: application/json
Accept-Language: zh-CN
Connection: keep-alive
Cookie: session=abc123
约 200-800 bytes 头部开销
**WebSocket 开销:**
数据帧头:2-14 bytes(根据 payload 长度)
后续消息仅 2-14 bytes 开销
**结论:** WebSocket 在频繁通信场景下带宽效率提升 10-50 倍
---
✅ **RESTful API**
✅ **页面加载**
✅ **文件上传/下载**
✅ **表单提交**
**代码示例(HTTP API):**
// 获取用户信息
const response = await fetch('/api/users/123', {
method: 'GET',
headers: { 'Accept': 'application/json' }
});
const user = await response.json();
// 创建订单
const order = await fetch('/api/orders', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ productId: 456, quantity: 2 })
});
✅ **实时聊天应用**
✅ **实时数据展示**
✅ **在线游戏**
✅ **实时通知**
✅ **物联网(IoT)**
**代码示例(WebSocket):**
// 客户端连接
const ws = new WebSocket('wss://example.com/chat');
ws.onopen = () => {
console.log('连接已建立');
ws.send(JSON.stringify({ type: 'join', room: 'general' }));
};
ws.onmessage = (event) => {
const message = JSON.parse(event.data);
console.log('收到消息:', message);
// 更新 UI
displayMessage(message);
};
ws.onerror = (error) => {
console.error('WebSocket 错误:', error);
};
ws.onclose = () => {
console.log('连接已关闭');
// 尝试重连
setTimeout(connect, 3000);
};
// 发送消息
function sendMessage(text) {
ws.send(JSON.stringify({ type: 'message', text: text }));
}
---
需要实时双向通信?
├─ 是 → 需要服务器主动推送?
│ ├─ 是 → 选择 WebSocket
│ └─ 否 → HTTP 轮询或 SSE
└─ 否 → 使用 HTTP
├─ 需要缓存?→ HTTP(天然支持)
├─ SEO 重要?→ HTTP(搜索引擎友好)
└─ 简单请求响应?→ HTTP(更简单)
很多应用同时使用 HTTP 和 WebSocket:
┌─────────────────────────────────────┐
│ 前端应用 │
├─────────────────────────────────────┤
│ HTTP: 用户认证、资源加载、API 调用 │
│ WebSocket: 实时消息、通知推送 │
└─────────────────────────────────────┘
│
├──── HTTP ────→ REST API 服务器
│
└──── WebSocket ─→ 实时通信服务器
**实际案例:**
---
**错误认知:** WebSocket 更先进,应该全部用 WebSocket
**实际情况:**
**正确做法:** 根据场景选择合适的协议,通常混合使用
**错误认知:** 用 setInterval 轮询就能实现实时效果
**实际问题:**
// 轮询方案(不推荐)
setInterval(() => {
fetch('/api/messages').then(updateUI);
}, 1000); // 每秒请求一次
// 问题:
// 1. 大量无效请求(无新消息时也请求)
// 2. 延迟高(最多 1 秒延迟)
// 3. 服务器压力大(N 用户 × 每秒 1 次 = N QPS)
**正确做法:** 使用 WebSocket 或 Server-Sent Events(SSE)
**错误认知:** 建立连接后就一劳永逸
**实际问题:**
**正确做法:** 实现自动重连机制
function connect() {
const ws = new WebSocket('wss://example.com/chat');
ws.onclose = () => {
// 指数退避重连策略
const delay = Math.min(1000 * Math.pow(2, reconnectAttempts), 30000);
reconnectAttempts++;
setTimeout(connect, delay);
};
ws.onopen = () => {
reconnectAttempts = 0; // 重置重连计数
};
}
---
| 安全措施 | 说明 |
|----------|------|
| HTTPS | 使用 TLS 加密传输 |
| CORS | 跨域资源共享控制 |
| CSRF Token | 防止跨站请求伪造 |
| 输入验证 | 防止 SQL 注入、XSS |
| 认证授权 | JWT、Session、OAuth |
| 安全措施 | 说明 |
|----------|------|
| WSS | 使用 TLS 加密(wss://) |
| Origin 检查 | 验证请求来源 |
| 身份验证 | 握手时或连接后认证 |
| 消息验证 | 验证消息格式和内容 |
| 速率限制 | 防止消息洪水攻击 |
| 连接数限制 | 防止资源耗尽 |
**WebSocket 安全示例:**
// 服务端验证(Node.js + ws 库)
const WebSocket = require('ws');
const wss = new WebSocket.Server({
port: 8080,
verifyClient: (info, callback) => {
// 验证 Origin
const allowedOrigins = ['https://example.com'];
if (allowedOrigins.includes(info.origin)) {
// 验证 Token
const token = info.req.headers['sec-websocket-protocol'];
if (verifyToken(token)) {
callback(true);
} else {
callback(false, 401, 'Unauthorized');
}
} else {
callback(false, 403, 'Forbidden');
}
}
});
---
// 推荐架构
class AppClient {
constructor() {
this.httpBase = 'https://api.example.com';
this.wsUrl = 'wss://realtime.example.com';
}
// 使用 HTTP 进行认证和资源加载
async login(credentials) {
const response = await fetch(${this.httpBase}/login, {
method: 'POST',
body: JSON.stringify(credentials)
});
return response.json();
}
// 使用 WebSocket 进行实时通信
connectRealtime(token) {
this.ws = new WebSocket(this.wsUrl);
this.ws.onopen = () => {
this.ws.send(JSON.stringify({ type: 'auth', token }));
};
}
// 根据场景选择协议
async fetchData(resourceId) {
// 历史数据用 HTTP
return fetch(${this.httpBase}/data/${resourceId});
}
subscribeUpdates(resourceId) {
// 实时更新用 WebSocket
this.ws.send(JSON.stringify({
type: 'subscribe',
resource: resourceId
}));
}
}
---
- 多路复用,减少连接数
- 头部压缩,减少开销
- 静态资源就近分发
- 减少源站压力
- Cache-Control 头
- ETag 验证
- Gzip/Brotli 压缩
- 图片优化
- 启用 permessage-deflate 扩展
- 二进制格式(Protocol Buffers、MessagePack)
// 定期发送 ping 保持连接
const heartbeat = setInterval(() => {
if (ws.readyState === WebSocket.OPEN) {
ws.ping();
}
}, 30000);
// 合并多个小消息
let buffer = [];
function sendMessage(data) {
buffer.push(data);
if (buffer.length >= 10) {
ws.send(JSON.stringify(buffer));
buffer = [];
}
}
- 限制单用户连接数
- 合理设置超时时间
---
| 特性 | HTTP/1.1 | HTTP/2 | HTTP/3 | WebSocket |
|------|----------|--------|--------|-----------|
| 传输层 | TCP | TCP | QUIC/UDP | TCP |
| 连接模式 | 短连接 | 多路复用 | 多路复用 | 长连接 |
| 通信方向 | 单向 | 单向 | 单向 | 双向 |
| 服务器推送 | 有限支持 | 支持 | 支持 | 原生支持 |
| 头部压缩 | 无 | HPACK | QPACK | 无(仅握手) |
| 队头阻塞 | 有 | 无(TCP 层仍有) | 无 | 无 |
| 延迟 | 中 | 低 | 最低 | 最低 |
| 适用场景 | 通用 | 通用 | 通用 | 实时通信 |
| 协议 | 默认端口 | 加密端口 |
|------|----------|----------|
| HTTP | 80 | - |
| HTTPS | - | 443 |
| WebSocket | 80 | - |
| WebSocket Secure | - | 443 |
---
---
---
**最后更新:** 2026-03-27
**本文地址:** https://www.tongxinxieyi.com/articles/15-websocket-vs-http-comparison.html