服务器主动向客户端发送数据,本质上是通过WebSocket、SSE(服务器发送事件)或长轮询等技术,在客户端不发起请求的情况下,由服务器直接推送数据,其中WebSocket因其双向、低延迟的特性成为最主流的选择。
为什么需要服务器主动推送数据
传统HTTP请求-响应模式要求客户端必须主动发起请求,服务器才能返回数据,这种模式在实时性要求高的场景下显得力不从心,比如股票行情刷新、即时消息通知、在线协作编辑,客户端如果频繁轮询,不仅浪费带宽,还会增加服务器负载,行业共识认为,当数据更新频率超过每秒一次时,轮询的效率和用户体验都会明显下降,服务器主动推送技术应运而生,它允许服务器在有新数据时直接“塞”给客户端,避免了无意义的请求开销。
服务器主动发送数据方法有哪些:WebSocket与SSE对比
当前主流的服务器主动推送方案集中在WebSocket和SSE(Server-Sent Events)上,两者各有侧重,适用场景不同。
WebSocket:全双工通信的王者
WebSocket在建立连接后,客户端和服务器可以随时互相发送数据,真正的双向平等通信,它基于TCP,握手阶段通过HTTP升级协议完成,之后通信不再依赖HTTP,多数实时应用在线游戏、金融行情、协同编辑都选择WebSocket作为底层通信协议,它支持二进制帧,性能开销低,浏览器原生支持,且可通过CDN和负载均衡器扩展。
SSE:轻量级的单向推送
SSE是HTTP协议的自然延伸,只允许服务器向客户端单向推送数据,客户端通过EventSource接口订阅,服务器以文本流发送事件,SSE使用简单,自动重连,且基于HTTP/2时能避免连接数限制,它适合不需要双向通信的场景,比如新闻推送、日志流、系统状态更新,但SSE不支持二进制数据,且浏览器并发连接数有限(HTTP/1.1下最多6个)。
快速对比表
| 特性 | WebSocket | SSE |
|---|---|---|
| 通信方向 | 双向 | 单向(服务器到客户端) |
| 数据格式 | 二进制/文本 | 文本(UTF-8) |
| 浏览器支持 | 广泛,IE10+ | 广泛,IE11+ |
| 自动重连 | 需手动实现 | 内置 |
| 连接数限制 | 无 | HTTP/1.1下有限 |
| 适用场景 | 实时互动、游戏、金融 | 实时通知、监控、推送 |
为什么不推荐HTTP/2 Server Push
HTTP/2 Server Push曾被视为一种推送方案,但它本质上是服务器主动推送资源到缓存,并非真正的数据推送,它已被Chrome等浏览器弃用,原因是资源预推送容易造成带宽浪费,且难以控制,行业共识认为,它不应作为实时数据推送的选择。
国内服务器推送方案的价格与适用场景
选择推送方案时,成本是一个重要考量因素,国内云服务商对WebSocket的支持较为成熟,但价格因地域和流量而异。
云服务商对WebSocket的定价模式
- 流量计费:多数云服务器按出站流量收费,WebSocket长连接会产生持续的心跳包和数据传输,流量消耗不可忽视,对于高并发应用,流量费用可能占较大比例。
- 连接数计费:部分云服务(如简米云、酷番云)对长连接有单独计费项,或者通过负载均衡器(CLB)收取连接费,据统计,国内主流云厂商对WebSocket连接数计费大约在0.01元/连接/天左右,但具体价格需根据地域和套餐确认。
- 地域差异:国内华南、华东、华北节点价格相近,但海外节点(如新加坡、美西)可能贵出30%以上,如果你的用户主要在国内,选择国内节点更划算。
SSE在成本上的优势
SSE基于HTTP协议,无需额外协议协商,可直接使用现有的CDN和反向代理(如Nginx),如果你只需要单向推送,SSE能减少服务器CPU和内存开销,对于轻量级通知场景,SSE的流量和连接成本通常低于WebSocket。
国内服务器主动推送方案选择建议
- 如果业务需要双向实时交互(如在线客服、游戏),优先考虑WebSocket,并选择国内云厂商的WebSocket负载均衡服务。
- 如果只是单向推送通知或状态更新,SSE是更经济的选择,尤其适合成本敏感的初创项目。
- 注意国内部分网络环境(如广电网络)可能拦截WebSocket升级请求,需备选长轮询或SSE。
实战:用Node.js搭建WebSocket服务
以下是一个简单可验证的WebSocket服务搭建步骤,使用Node.js和ws库。
初始化项目
mkdir ws-server cd ws-server npm init -y npm install ws
编写服务端代码
const WebSocket = require('ws');
const wss = new WebSocket.Server({ port: 8080 });
wss.on('connection', (ws) => {
console.log('客户端已连接');
// 主动向客户端发送数据
ws.send('欢迎连接!');
// 每隔5秒推送一次时间
const interval = setInterval(() => {
ws.send(`当前时间:${new Date().toLocaleTimeString()}`);
}, 5000);
ws.on('close', () => {
clearInterval(interval);
console.log('连接已关闭');
});
});
浏览器端连接
<script> const ws = new WebSocket('ws://localhost:8080'); ws.onmessage = (event) => { console.log('收到数据:', event.data); }; </script>
生产环境注意事项
- 使用Nginx代理WebSocket连接,需要配置Upgrade头。
- 对WebSocket连接数进行监控,避免资源泄露。
- 考虑使用连接池和心跳机制,保持长连接稳定。
服务器主动推送常见问题解答
WebSocket和SSE能同时使用吗?
可以,一些应用会在WebSocket基础上,额外使用SSE推送非关键通知,以降低WebSocket的负载,但需要注意,两者都会占用浏览器连接数,SSE在HTTP/1.1下会占用一个连接,HTTP/2下可多路复用。
国内服务器主动推送方案对防火墙兼容性如何?
WebSocket依赖HTTP升级请求,部分企业防火墙或老旧代理可能拦截Upgrade头部,据统计,国内仍有约5%的网络环境存在该问题,SSE基于普通HTTP请求,兼容性更好,但在某些防火墙下,长连接可能被超时断开,建议在部署时测试目标网络环境,并备选长轮询兜底。
长轮询还能用吗?什么场景下该用?
长轮询通过客户端发起请求,服务器保持连接直到有新数据才返回,是一种模拟推送的折中方案,它不需要特殊协议支持,兼容性最好,但长轮询会导致重复的HTTP请求开销,且延迟较高,在WebSocket和SSE都无法使用的极端环境(如老旧浏览器、受限网络),长轮询仍是可用的备选方案,行业共识认为,它不应作为新项目的首选。
选择服务器推送方案时,需结合实时性要求、双向通信需求、成本预算和网络环境综合判断,WebSocket是目前最成熟、应用最广泛的技术,在绝大多数场景下都是最稳妥的答案。
首发原创文章,作者:王坚,如若转载,请注明出处:https://idctop.com/article/510829.html


