Spring Boot 实现网页消息推送的 5 种主流方式(2025–2026 实战指南)
网页消息推送(实时通知、聊天、状态更新、订单提醒等)是现代 Web 应用的核心功能之一。Spring Boot 提供了非常成熟的支持,下面整理出目前最常用、最实用的 5 种实现方式,从简单到高级排序,并标注适用场景、优缺点和核心代码要点。
1. 短轮询(Short Polling) + Ajax / Fetch
原理:前端定时(每 3–10 秒)通过 Ajax / Fetch 向后端拉取新消息。
适用场景:对实时性要求不高、开发周期短、兼容性极强
优点:实现最简单,无需额外依赖,兼容所有浏览器
缺点:服务器压力大(大量无效请求)、延迟高、不够“实时”
核心代码(后端):
@RestController
public class NotificationController {
@GetMapping("/notifications")
public ResponseEntity<List<String>> getNotifications() {
// 查询是否有新消息(数据库 / Redis / 内存队列)
List<String> newMsgs = notificationService.pollNewMessages();
return ResponseEntity.ok(newMsgs);
}
}
前端(Vue/React 通用):
setInterval(async () => {
const res = await fetch('/notifications');
const data = await res.json();
if (data.length > 0) addNotifications(data);
}, 5000);
2. 长轮询(Long Polling)
原理:客户端发起请求,后端如果没有新消息就挂起请求(不返回),有新消息立即返回;前端收到后立即再发起下一次请求。
适用场景:实时性要求较高,但不想引入 WebSocket/SSE
优点:比短轮询节省资源,实现相对简单
缺点:连接频繁建立/断开,服务器需维护大量长连接
后端实现(使用 DeferredResult):
@GetMapping("/long-poll")
public DeferredResult<List<String>> longPoll() {
DeferredResult<List<String>> result = new DeferredResult<>(30000L); // 30秒超时
// 异步监听新消息(可使用消息队列或 BlockingQueue)
messageQueue.addListener(msg -> {
if (!result.isSetOrExpired()) {
result.setResult(Collections.singletonList(msg));
}
});
result.onTimeout(() -> result.setResult(Collections.emptyList()));
return result;
}
3. Server-Sent Events(SSE)
原理:基于 HTTP 的单向服务器推送,客户端使用 EventSource 建立持久连接,服务端通过 text/event-stream 推送事件。
适用场景:服务器 → 客户端单向推送(如通知、进度、股票价格、日志监控)
优点:实现简单、自动重连、基于标准 HTTP、资源消耗比 WebSocket 低
缺点:单向(客户端不能主动发消息)、不支持二进制
后端核心代码(Spring Boot 推荐方式):
@GetMapping(value = "/sse", produces = MediaType.TEXT_EVENT_STREAM_VALUE)
public Flux<ServerSentEvent<String>> sseNotifications() {
return Flux.interval(Duration.ofSeconds(1))
.map(seq -> ServerSentEvent.<String>builder()
.id(String.valueOf(seq))
.event("message")
.data("服务器推送:" + LocalDateTime.now())
.build());
}
或使用 SseEmitter(更灵活,支持断开重连):
@GetMapping("/notifications")
public SseEmitter stream() {
SseEmitter emitter = new SseEmitter(Long.MAX_VALUE);
// 在其他地方调用 emitter.send() 推送
return emitter;
}
前端:
const source = new EventSource('/sse');
source.onmessage = e => console.log('收到:', e.data);
4. WebSocket(原生 / @ServerEndpoint)
原理:全双工通信通道,浏览器和服务器建立持久 TCP 连接。
适用场景:需要双向实时通信(聊天、协作编辑、游戏)
优点:真正的实时双向、低延迟
缺点:实现稍复杂、需处理断线重连、心跳
Spring Boot 简单实现:
@ServerEndpoint("/ws/{userId}")
@Component
public class WebSocketEndpoint {
private static final Map<String, Session> sessions = new ConcurrentHashMap<>();
@OnOpen
public void onOpen(Session session, @PathParam("userId") String userId) {
sessions.put(userId, session);
}
@OnMessage
public void onMessage(String message, Session session) {
// 广播或点对点
}
public static void sendToUser(String userId, String msg) {
Session session = sessions.get(userId);
if (session != null && session.isOpen()) {
session.getAsyncRemote().sendText(msg);
}
}
}
配置:
@Configuration
@EnableWebSocket
public class WebSocketConfig implements WebSocketConfigurer {
@Override
public void registerWebSocketHandlers(WebSocketHandlerRegistry registry) {
registry.addHandler(new MyWebSocketHandler(), "/my-ws").setAllowedOrigins("*");
}
}
5. WebSocket + STOMP(最推荐的生产方式)
原理:在 WebSocket 上层使用 STOMP 协议(类似 HTTP 的消息协议),支持订阅主题、点对点、广播等。
适用场景:几乎所有中大型实时应用(聊天、通知、实时仪表盘、订单状态)
优点:功能强大(订阅/取消订阅、断线重连、消息确认)、易于管理用户会话、支持广播/点对点
依赖:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-websocket</artifactId>
</dependency>
配置:
@Configuration
@EnableWebSocketMessageBroker
public class WebSocketConfig implements WebSocketMessageBrokerConfigurer {
@Override
public void configureMessageBroker(MessageBrokerRegistry config) {
config.enableSimpleBroker("/topic", "/queue"); // 订阅前缀
config.setApplicationDestinationPrefixes("/app"); // 发送前缀
config.setUserDestinationPrefix("/user"); // 点对点前缀
}
@Override
public void registerStompEndpoints(StompEndpointRegistry registry) {
registry.addEndpoint("/ws")
.setAllowedOriginPatterns("*")
.withSockJS(); // 支持降级
}
}
发送消息(广播):
@Autowired
private SimpMessagingTemplate messagingTemplate;
public void sendNotification(String message) {
messagingTemplate.convertAndSend("/topic/notifications", message);
}
点对点(需结合 Spring Security 或自定义 Principal):
messagingTemplate.convertAndSendToUser(username, "/queue/notifications", message);
前端(使用 stomp.js 或 @stomp/stompjs):
const client = new Client({
brokerURL: 'ws://localhost:8080/ws',
onConnect: () => {
client.subscribe('/topic/notifications', msg => console.log(msg.body));
client.subscribe('/user/queue/notifications', msg => console.log(msg.body));
}
});
client.activate();
总结对比表
| 方式 | 实时性 | 方向性 | 复杂度 | 资源消耗 | 推荐场景 |
|---|---|---|---|---|---|
| 短轮询 | ★☆☆☆☆ | 双向 | 最低 | 高 | 原型、兼容性要求极高 |
| 长轮询 | ★★☆☆☆ | 双向 | 低 | 中 | 中等实时性 |
| SSE | ★★★★☆ | 服务器→客户端 | 低 | 低 | 服务器单向推送首选 |
| 原生 WebSocket | ★★★★★ | 双向 | 中 | 中 | 简单双向场景 |
| WebSocket + STOMP | ★★★★★ | 双向 | 中高 | 中 | 生产级实时应用首选 |
2026 年推荐优先级:
大多数场景 → WebSocket + STOMP
纯服务器推送、资源敏感 → SSE
简单/原型 → 轮询
你现在项目里想实现哪种推送?是聊天、通知、进度条还是其他?可以告诉我具体需求,我可以给出更详细的代码和配置。