页面实时获取数据方案全解析:从轮询到 WebSocket 与 SSE
在实时交互场景中(如即时聊天、实时数据监控、在线协作工具),前端需要实时获取后端数据。传统的 “请求 - 响应” 模式无法满足实时性需求,因此衍生出轮询、WebSocket、SSE 等技术方案。本文将详细解析三种方案的原理、实现、优缺点及适用场景,帮助开发者选择合适的实时数据获取方式。
方案一:轮询(Polling)
轮询是最直观的实时数据获取方式,通过前端定时发送请求,后端返回最新数据,实现 “准实时” 效果。
原理
- 前端:使用定时器(如
setInterval)每隔固定时间(如 1 秒)向后端发送 HTTP 请求;
- 后端:收到请求后,立即返回当前最新数据(无论是否有更新);
- 特点:基于 HTTP 协议,无需特殊协议支持,实现简单。
实现示例
(1)前端代码
1 2 3 4 5 6 7 8 9 10
| setInterval(() => { fetch("/api/realtime-data") .then(response => response.json()) .then(data => { console.log("最新数据:", data); }) .catch(error => console.error("请求失败:", error)); }, 1000);
|
(2)后端代码(Java Servlet)
1 2 3 4 5 6 7 8 9 10
| @WebServlet("/api/realtime-data") public class RealtimeDataServlet extends HttpServlet { @Override protected void doGet(HttpServletRequest request, HttpServletResponse response) throws IOException { response.setContentType("application/json;charset=UTF-8"); String data = "{\"onlineUsers\":" + (int)(Math.random() * 100) + ", \"timestamp\":" + System.currentTimeMillis() + "}"; response.getWriter().write(data); } }
|
优缺点
优点:
- 实现简单:无需特殊协议或后端配置,前端仅需定时器 + HTTP 请求;
- 兼容性好:支持所有浏览器和服务器,无技术门槛。
缺点:
- 资源浪费:无论数据是否更新,前端都会定时发送请求,无效请求占比高(如数据 10 秒才更新一次,1 秒一次的请求有 9 次无效);
- 实时性差:数据更新延迟取决于轮询间隔(间隔 1 秒则最大延迟 1 秒);
- 服务器压力大:高频请求会占用大量连接和带宽资源。
适用场景
- 实时性要求低的场景(如数据 5-10 分钟更新一次);
- 简单的小型应用(如个人博客的访问量统计);
- 对兼容性要求极高,无法使用 WebSocket/SSE 的环境。
方案二:WebSocket(全双工实时通信)
WebSocket 是 HTML5 定义的全双工通信协议,通过一次 TCP 连接实现客户端与服务器的双向实时通信,摆脱了 HTTP “请求 - 响应” 模式的限制。
原理
- 连接建立:客户端通过
ws://或wss://协议发送握手请求,服务器响应后建立持久 TCP 连接;
- 双向通信:连接建立后,服务器可主动向客户端推送数据,客户端也可随时向服务器发送数据(全双工);
- 特点:基于 TCP 协议,连接一旦建立,无需重复握手,数据传输高效。
实现示例
(1)前端代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36
| <!DOCTYPE html> <html> <body> <div id="messageList"></div> <script> const socket = new WebSocket("ws://localhost:8080/ws");
socket.onopen = (event) => { console.log("WebSocket连接已建立"); socket.send("客户端已就绪"); };
socket.onmessage = (event) => { const messageList = document.getElementById("messageList"); const message = document.createElement("p"); message.textContent = "服务器推送:" + event.data; messageList.appendChild(message); };
socket.onclose = (event) => { console.log("WebSocket连接已关闭,代码:" + event.code); };
socket.onerror = (error) => { console.error("WebSocket错误:", error); }; </script> </body> </html>
|
(2)后端代码(Java WebSocket)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40
| import javax.websocket.OnClose; import javax.websocket.OnMessage; import javax.websocket.OnOpen; import javax.websocket.Session; import javax.websocket.server.ServerEndpoint; import java.io.IOException; import java.util.concurrent.CopyOnWriteArraySet;
@ServerEndpoint("/ws") public class WebSocketServer { private static final CopyOnWriteArraySet<Session> sessions = new CopyOnWriteArraySet<>();
@OnOpen public void onOpen(Session session) { System.out.println("新客户端连接,会话ID:" + session.getId()); sessions.add(session); }
@OnMessage public void onMessage(String message, Session session) throws IOException { System.out.println("收到客户端消息:" + message); for (Session s : sessions) { if (s.isOpen()) { s.getBasicRemote().sendText("服务器收到:" + message); } } }
@OnClose public void onClose(Session session) { System.out.println("客户端断开连接,会话ID:" + session.getId()); sessions.remove(session); } }
|
优缺点
优点:
- 实时性强:服务器可主动推送数据,无延迟(毫秒级响应);
- 高效性:一次 TCP 连接复用到底,避免 HTTP 重复握手(三次握手、四次挥手)的开销;
- 双向通信:支持客户端与服务器双向实时交互(如即时聊天、协作编辑)。
缺点:
- 实现复杂:需后端支持 WebSocket 协议(如 Tomcat 7+、Spring WebSocket),前端需处理连接状态(断开重连等);
- 兼容性限制:老式浏览器(如 IE 10 以下)不支持,需降级方案;
- 资源占用:长连接会占用服务器 TCP 连接资源,高并发场景需优化(如连接池、心跳检测)。
适用场景
- 实时双向交互场景(如即时通讯、在线游戏、协作工具);
- 高实时性要求场景(如股票行情、实时监控数据);
- 频繁数据交互场景(避免轮询的无效请求浪费)。
方案三:SSE(Server-Sent Events,服务器推送事件)
SSE 是 HTML5 定义的基于 HTTP 的单向通信协议,允许服务器通过长连接主动向客户端推送数据,客户端无需发送请求。
原理
- 连接建立:客户端通过普通 HTTP 请求(
GET)连接后端 SSE 端点,服务器返回特殊响应头(Content-Type: text/event-stream),维持长连接;
- 单向通信:仅服务器可向客户端推送数据,客户端无法主动发送数据(单向);
- 特点:基于 HTTP 协议,无需新协议支持,实现比 WebSocket 简单,适合 “服务器推、客户端收” 的场景。
实现示例
(1)前端代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34
| <!DOCTYPE html> <html> <body> <div id="dataContainer"></div> <script> const eventSource = new EventSource("/events");
eventSource.onopen = () => { console.log("SSE连接已建立"); };
eventSource.onmessage = (event) => { const container = document.getElementById("dataContainer"); const dataElement = document.createElement("p"); dataElement.textContent = "收到数据:" + event.data; container.appendChild(dataElement); };
eventSource.addEventListener("error", (event) => { console.error("SSE错误:", event.data); });
eventSource.onerror = () => { console.log("SSE连接出错,尝试重连..."); }; </script> </body> </html>
|
(2)后端代码(Java Servlet)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42
| import javax.servlet.annotation.WebServlet; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.IOException; import java.io.PrintWriter; import java.util.Date;
@WebServlet("/events") public class SSEServlet extends HttpServlet { @Override protected void doGet(HttpServletRequest request, HttpServletResponse response) throws IOException { response.setContentType("text/event-stream"); response.setCharacterEncoding("UTF-8"); response.setHeader("Cache-Control", "no-cache"); response.setHeader("Connection", "keep-alive");
PrintWriter writer = response.getWriter(); try { while (true) { String data = "data: 实时数据更新,时间:" + new Date() + "\n\n"; writer.write(data); writer.flush();
Thread.sleep(2000);
if (writer.checkError()) { break; } } } catch (InterruptedException e) { e.printStackTrace(); } finally { writer.close(); } } }
|
SSE 消息格式
SSE 推送的消息需遵循特定格式,否则客户端无法正确解析:
优缺点
优点:
- 实现简单:基于 HTTP 协议,后端无需特殊协议支持,前端仅需
EventSource对象;
- 自动重连:
EventSource会自动处理连接断开后的重连(默认重试间隔);
- 轻量级:适合单向推送场景,无需处理双向通信的复杂性。
缺点:
- 单向通信:仅支持服务器向客户端推送,客户端无法主动发送数据;
- 数据大小限制:单次推送数据量有限(依赖 HTTP 响应大小限制);
- 兼容性:IE 浏览器完全不支持(需使用 polyfill 兼容)。
适用场景
- 单向实时推送场景(如实时新闻通知、股票行情更新、监控告警);
- 对实现复杂度敏感,无需双向交互的场景;
- 基于 HTTP 生态,希望复用现有服务器配置(如反向代理、认证)的场景。
三种方案对比与选择指南
| 维度 |
轮询 |
WebSocket |
SSE |
| 通信方向 |
单向(客户端请求) |
双向(全双工) |
单向(服务器推送) |
| 连接类型 |
短连接(多次 HTTP) |
长连接(TCP 复用) |
长连接(HTTP 复用) |
| 实时性 |
低(取决于间隔) |
高(毫秒级) |
高(毫秒级) |
| 实现复杂度 |
低(仅 HTTP) |
中(需协议支持) |
低(基于 HTTP) |
| 兼容性 |
所有浏览器 |
现代浏览器(IE10+) |
现代浏览器(IE 不支持) |
| 带宽效率 |
低(无效请求多) |
高(无重复握手) |
高(无重复握手) |
| 适用场景 |
低实时性、简单场景 |
双向交互、高实时性 |
单向推送、轻量场景 |
选择建议:
- 简单场景,实时性要求低:选轮询(如后台数据每 5 分钟更新一次);
- 双向交互,高实时性:选 WebSocket(如即时聊天、在线游戏);
- 单向推送,轻量需求:选 SSE(如新闻推送、实时监控数据展示)
v1.3.10