Implementing Web Message Push: Short Polling, Long Polling, Iframe Stream, SSE, MQTT, and WebSocket
This article explains several server‑side techniques for real‑time web message push—including short and long polling, hidden‑iframe streaming, Server‑Sent Events, MQTT, and WebSocket—provides their principles, advantages, drawbacks, and complete Spring Boot/Java code examples for each approach.
When a web application needs to display a notification badge (the small red dot) for unread messages, the core requirement is to increment the count in real time whenever an event occurs, such as a user sharing a resource or the backend pushing a new message.
What is Push?
Push (or push ) refers to the proactive delivery of messages from a server to a client, commonly used in scenarios like notifying a user when they follow a public account.
Push can be divided into web push and mobile push . The former includes site‑internal messages, unread email counts, monitoring alerts, etc.
Short Polling
Short polling uses a simple JavaScript timer to send an HTTP request at a fixed interval (e.g., every second) to fetch the unread count.
setInterval(() => {
// request unread count
messageCount().then(res => {
if (res.code === 200) {
this.messageCount = res.data;
}
})
}, 1000);While easy to implement, it generates unnecessary traffic because the client requests even when there is no new data.
Long Polling
Long polling keeps the HTTP connection open until the server has new data, reducing request overhead. The article demonstrates a Spring Boot implementation using DeferredResult (Servlet 3.0) and Guava Multimap to store pending requests.
@Controller
@RequestMapping("/polling")
public class PollingController {
public static Multimap
> watchRequests =
Multimaps.synchronizedMultimap(HashMultimap.create());
@GetMapping("watch/{id}")
@ResponseBody
public DeferredResult
watch(@PathVariable String id) {
DeferredResult
dr = new DeferredResult<>(TIME_OUT);
dr.onCompletion(() -> watchRequests.remove(id, dr));
watchRequests.put(id, dr);
return dr;
}
@GetMapping("publish/{id}")
@ResponseBody
public String publish(@PathVariable String id) {
if (watchRequests.containsKey(id)) {
for (DeferredResult
dr : watchRequests.get(id)) {
dr.setResult("Updated " + new Date());
}
}
return "success";
}
}If the request times out, an AsyncRequestTimeoutException is thrown and handled globally with @ControllerAdvice to return a 304 status.
Iframe Stream
A hidden <iframe> continuously requests an API that writes JavaScript snippets to the response, updating the page via DOM manipulation.
<iframe src="/iframe/message" style="display:none"></iframe>Although simple, browsers show a loading spinner, which can be visually distracting.
Server‑Sent Events (SSE)
SSE uses a single HTTP connection that streams text/event-stream data from server to client. It is unidirectional, works over plain HTTP, and automatically reconnects.
let source = null;
if (window.EventSource) {
source = new EventSource('http://localhost:7777/sse/sub/' + userId);
source.addEventListener('open', e => setMessageInnerHTML('Connection opened'));
source.addEventListener('message', e => setMessageInnerHTML(e.data));
} else {
setMessageInnerHTML('Your browser does not support SSE');
}On the server side, a SseEmitter is stored in a map and used to send messages to specific users.
MQTT
MQTT (Message Queue Telemetry Transport) is a lightweight publish/subscribe protocol built on top of TCP/IP, ideal for IoT scenarios where devices need reliable, asynchronous messaging.
WebSocket
WebSocket establishes a full‑duplex TCP connection, allowing both client and server to send messages at any time. The article provides a Spring Boot example using @ServerEndpoint and a JavaScript client.
@Component
@ServerEndpoint("/websocket/{userId}")
public class WebSocketServer {
private Session session;
private static final CopyOnWriteArraySet
webSockets = new CopyOnWriteArraySet<>();
private static final Map
sessionPool = new HashMap<>();
@OnOpen
public void onOpen(Session session, @PathParam("userId") String userId) {
this.session = session;
webSockets.add(this);
sessionPool.put(userId, session);
}
@OnMessage
public void onMessage(String message) {
// handle incoming message
}
public void sendOneMessage(String userId, String message) {
Session s = sessionPool.get(userId);
if (s != null && s.isOpen()) {
s.getAsyncRemote().sendText(message);
}
}
}Each method has its own trade‑offs; the article concludes with a recommendation to choose the solution that best fits the specific business scenario and mentions third‑party services (e.g., GoEasy, Jiguang) for quick integration.
Custom Push Solutions
In real projects, developers often combine several techniques or rely on dedicated push platforms that handle content moderation, audience targeting, rate limiting, and failure compensation.
All the sample code is available on the author's GitHub repository.
IT Services Circle
Delivering cutting-edge internet insights and practical learning resources. We're a passionate and principled IT media platform.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.