对话的边界:HTTP 的克制,SSE 的流淌,WebSocket 的自由

写在前面

"前后端交互,不就是前端调后端接口,后端返回 JSON 吗?"

这是大多数后端开发者的第一反应。我们习惯了 HTTP 请求-响应模式,却忽略了"数据交互"还有另外两种重要的方式。直到我接触 RAG 项目,需要实现"逐字输出"的效果时,才发现:原来 SSE(Server-Sent Events)可以让服务端像打字机一样把内容推给前端。

后来做直播间弹幕,又接触了 WebSocket:服务器能主动推送,客户端也能随时发消息,真正的"双向实时"。

这三种技术,就像三种不同的"对话方式":

  • HTTP:你问一句,我答一句。问完结束。

  • SSE:你说开始,我就一直说,你只听不说。

  • WebSocket:咱们随时可以说,谁想说话就说,像打电话。

今天,我们就从原理到实战,彻底搞清这三者的区别、优缺点和适用场景。读完这篇,你不仅能对付面试官,还能在实际项目中做出更合理的技术选型。

一、HTTP:最熟悉的"一问一答"

1.1 工作原理

HTTP(HyperText Transfer Protocol)是建立在 TCP 之上的应用层协议,核心特征是请求-响应模型

  1. 客户端(如浏览器)发起一个请求

  2. 服务端处理请求,返回响应

  3. 连接关闭(短连接),或保持一段时间(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 工作原理

  1. 客户端发起一个特殊的 HTTP 请求(Accept: text/event-stream

  2. 服务端保持连接打开,并定期或按需发送 data: 格式的消息

  3. 客户端通过 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 工作原理

  1. 客户端发起 HTTP 请求,头部包含 Upgrade: websocket

  2. 服务端同意升级,返回 101 Switching Protocols

  3. 连接升级为 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 更高效,延迟更低。

六、实践建议:如何选择和使用?

  1. 默认用 HTTP:绝大多数场景 HTTP 足够,不要为了"实时"而提前优化。

  2. 只要服务端推数据,优先选 SSE:比 WebSocket 简单很多,且基于 HTTP,运维友好。

  3. 需要双向实时交互,再考虑 WebSocket:比如你做的直播间弹幕。

  4. 注意连接数限制:SSE 和 WebSocket 都会占用长连接,浏览器同域名限制 6 个,服务端也需要考虑并发上限。

  5. 降级方案:WebSocket 可以用 SockJS + STOMP 降级到 HTTP 流式或长轮询。

在日常开发中,我习惯这样组合:

  • 普通 API → HTTP

  • AI 对话 / 进度通知 → SSE

  • 即时通讯 / 游戏 → WebSocket

总结:没有最好,只有最合适

HTTP、SSE、WebSocket 并不是替代关系,而是不同场景下的最佳工具。理解它们的区别,就像知道什么时候用卡车、什么时候用轿车、什么时候用摩托车------都能载人,但效率完全不同。

下次你接到一个需求:

  • 只需要前端调后端接口 → HTTP

  • 需要服务器像打字机一样输出 → SSE

  • 需要双向实时聊天 → WebSocket

选对了,代码写起来顺手,用户体验也好。选错了,要么大炮打蚊子,要么马车跑高速。

假设你要实现一个"在线考试系统",需要实时显示剩余时间、实时接收老师发布的公告,但考生不需要发送消息(除了提交答案)。同时,系统需要支持数千人同时考试。你会选择 HTTP、SSE 还是 WebSocket?为什么?欢迎在评论区写下你的技术选型和理由。

相关推荐
危桥带雨1 小时前
FLASH代码部分
java·后端·spring
逍遥德2 小时前
skill模板-基于java maven项目
java·人工智能·自然语言处理·maven
XiYang-DING2 小时前
【Java EE】单例模式
java·单例模式·java-ee
Rust研习社2 小时前
添加依赖库时的 features 是什么?优雅实现编译期条件编译与模块化开发
开发语言·后端·rust
志飞2 小时前
springboot配置可持久化本地缓存ehcache
java·spring boot·缓存·ehcache·ehcache持久化
itzixiao2 小时前
L1-051 打折(5分)[java][python]
java·python·算法
马艳泽3 小时前
接到新需求后快速产出可执行的方案和时间估算
后端
小心我捶你啊3 小时前
VPS的主要用途,与其它方式的区别
服务器·网络协议·tcp/ip
それども3 小时前
Spring Bean 注入的优先级顺序
java·数据库·sql·spring