写在前面
"前后端交互,不就是前端调后端接口,后端返回 JSON 吗?"
这是大多数后端开发者的第一反应。我们习惯了 HTTP 请求-响应模式,却忽略了"数据交互"还有另外两种重要的方式。直到我接触 RAG 项目,需要实现"逐字输出"的效果时,才发现:原来 SSE(Server-Sent Events)可以让服务端像打字机一样把内容推给前端。
后来做直播间弹幕,又接触了 WebSocket:服务器能主动推送,客户端也能随时发消息,真正的"双向实时"。
这三种技术,就像三种不同的"对话方式":
-
HTTP:你问一句,我答一句。问完结束。
-
SSE:你说开始,我就一直说,你只听不说。
-
WebSocket:咱们随时可以说,谁想说话就说,像打电话。
今天,我们就从原理到实战,彻底搞清这三者的区别、优缺点和适用场景。读完这篇,你不仅能对付面试官,还能在实际项目中做出更合理的技术选型。

一、HTTP:最熟悉的"一问一答"
1.1 工作原理
HTTP(HyperText Transfer Protocol)是建立在 TCP 之上的应用层协议,核心特征是请求-响应模型:
-
客户端(如浏览器)发起一个请求
-
服务端处理请求,返回响应
-
连接关闭(短连接),或保持一段时间(Keep-Alive)

1.2 实现方式(Java)
java
@RestController
public class UserController {
@GetMapping("/api/user")
public User getUser() {
return new User("张三", 18);
}
}
1.3 优缺点

1.4 适用场景
-
普通 CRUD 接口
-
RESTful API
-
文件上传/下载
-
不需要实时更新的页面(后台管理系统)
如果你需要"服务器主动发消息"或"实时双向通信",HTTP 就不够用了。
二、SSE:服务端单向推送的"广播员"
SSE(Server-Sent Events)是 HTML5 规范的一部分,允许服务端通过 HTTP 协议单向 向客户端推送事件流。客户端通过 EventSource API 接收。
你体验过的"AI 逐字输出"(ChatGPT 式打字效果),背后就是 SSE。
2.1 工作原理
-
客户端发起一个特殊的 HTTP 请求(
Accept: text/event-stream) -
服务端保持连接打开,并定期或按需发送
data:格式的消息 -
客户端通过
onmessage回调逐条接收,连接可以一直保持

2.2 实现方式(Java + Spring)
Spring 从 4.2 开始支持 SSE,使用 SseEmitter:
java
@RestController
public class SseController {
@GetMapping(value = "/stream", produces = MediaType.TEXT_EVENT_STREAM_VALUE)
public SseEmitter stream() {
SseEmitter emitter = new SseEmitter();
// 异步线程推送
executor.execute(() -> {
for (int i = 0; i < 10; i++) {
emitter.send("消息 " + i);
Thread.sleep(1000);
}
emitter.complete();
});
return emitter;
}
}
前端接收:
javascript
const eventSource = new EventSource('/stream');
eventSource.onmessage = (event) => {
console.log('收到:', event.data);
};
2.3 优缺点

2.4 适用场景
-
AI 流式对话(RAG、ChatGPT 式逐字输出)
-
实时股票行情、体育比分
-
服务器日志实时展示
-
新闻推送、系统通知
在 RAG 项目中用 SSE 做流式输出,正是最佳实践------既实现了实时感,又比 WebSocket 简单得多。
三、WebSocket:真正的全双工"电话线"
WebSocket 是一个独立的协议(ws:// / wss://),它在 HTTP 握手后升级为持久连接,实现了客户端和服务端之间任意时刻的双向通信。
3.1 工作原理
-
客户端发起 HTTP 请求,头部包含
Upgrade: websocket -
服务端同意升级,返回
101 Switching Protocols -
连接升级为 WebSocket 协议,之后双方可以随时互发消息

3.2 实现方式(Java + Spring WebSocket)
java
@Configuration
@EnableWebSocketMessageBroker
public class WebSocketConfig implements WebSocketMessageBrokerConfigurer {
@Override
public void registerStompEndpoints(StompEndpointRegistry registry) {
registry.addEndpoint("/ws").withSockJS();
}
@Override
public void configureMessageBroker(MessageBrokerRegistry registry) {
registry.enableSimpleBroker("/topic");
registry.setApplicationDestinationPrefixes("/app");
}
}
前端(使用 STOMP 协议):
javascript
const socket = new SockJS('/ws');
const stompClient = Stomp.over(socket);
stompClient.connect({}, () => {
stompClient.subscribe('/topic/room/123', (msg) => {
console.log('弹幕:', msg.body);
});
});
// 发送弹幕
stompClient.send('/app/chat', {}, JSON.stringify({content: '666'}));
3.3 优缺点

3.4 适用场景
-
直播间弹幕、聊天室
-
在线游戏(实时位置同步)
-
协同编辑文档(如 Google Docs)
-
实时监控仪表盘
-
需要双向消息的任何应用
直播间弹幕,确实是非 WebSocket 不可的场景------因为客户端需要随时发送,服务端也要随时广播给所有人。
四、三者对比:一张表看懂选型

选型决策图

五、面试常见问题及回答思路
问:SSE 和 WebSocket 有什么区别?什么时候用 SSE,什么时候用 WebSocket?
答:SSE 是单向推送(服务端→客户端),基于 HTTP,实现简单,自动重连,适合流式输出、通知推送。WebSocket 是全双工双向通信,协议独立,支持二进制,适合聊天室、游戏等场景。如果只需要服务端推送,选 SSE;如果需要客户端也能随时发消息,选 WebSocket。
问:SSE 和长轮询(Long Polling)有什么区别?
答:长轮询是客户端发起请求,服务端挂起连接直到有数据才返回,然后客户端立即再发起新请求。SSE 是真正的长连接,服务端可以连续发送多个事件,无需客户端反复请求。SSE 更高效,延迟更低。
六、实践建议:如何选择和使用?
-
默认用 HTTP:绝大多数场景 HTTP 足够,不要为了"实时"而提前优化。
-
只要服务端推数据,优先选 SSE:比 WebSocket 简单很多,且基于 HTTP,运维友好。
-
需要双向实时交互,再考虑 WebSocket:比如你做的直播间弹幕。
-
注意连接数限制:SSE 和 WebSocket 都会占用长连接,浏览器同域名限制 6 个,服务端也需要考虑并发上限。
-
降级方案:WebSocket 可以用 SockJS + STOMP 降级到 HTTP 流式或长轮询。
在日常开发中,我习惯这样组合:
-
普通 API → HTTP
-
AI 对话 / 进度通知 → SSE
-
即时通讯 / 游戏 → WebSocket
总结:没有最好,只有最合适
HTTP、SSE、WebSocket 并不是替代关系,而是不同场景下的最佳工具。理解它们的区别,就像知道什么时候用卡车、什么时候用轿车、什么时候用摩托车------都能载人,但效率完全不同。
下次你接到一个需求:
-
只需要前端调后端接口 → HTTP
-
需要服务器像打字机一样输出 → SSE
-
需要双向实时聊天 → WebSocket
选对了,代码写起来顺手,用户体验也好。选错了,要么大炮打蚊子,要么马车跑高速。
假设你要实现一个"在线考试系统",需要实时显示剩余时间、实时接收老师发布的公告,但考生不需要发送消息(除了提交答案)。同时,系统需要支持数千人同时考试。你会选择 HTTP、SSE 还是 WebSocket?为什么?欢迎在评论区写下你的技术选型和理由。