Backend Development 10 min read

Mastering WebSocket with Spring Boot 3: From Handshake to Real‑Time Messaging

An in‑depth Spring Boot 3 tutorial explains WebSocket fundamentals, the HTTP upgrade handshake, core Spring APIs, configuration options, origin handling, and testing steps, enabling developers to build real‑time, bidirectional communication services for web applications.

Spring Full-Stack Practical Cases
Spring Full-Stack Practical Cases
Spring Full-Stack Practical Cases
Mastering WebSocket with Spring Boot 3: From Handshake to Real‑Time Messaging

WebSocket Introduction

WebSocket protocol RFC 6455 provides a standardized way to establish a full-duplex, bidirectional communication channel over a single TCP connection between client and server. It works over HTTP ports 80/443 and can reuse existing firewall rules.

The interaction starts with an HTTP request that includes an Upgrade header to switch to the WebSocket protocol. Example request:

<code>GET /spring-websocket-portfolio/portfolio HTTP/1.1
Host: localhost:8080
Upgrade: websocket             // ①
Connection: Upgrade           // ②
Sec-WebSocket-Key: Uc9l9TMkWGbHFD2qnFHltg==
Sec-WebSocket-Protocol: v10.stomp, v11.stomp
Sec-WebSocket-Version: 13
Origin: http://localhost:8080</code>

① Upgrade header information ② Use Upgrade connection

A WebSocket‑supporting server responds with a 101 Switching Protocols status instead of the usual 200:

<code>HTTP/1.1 101 Switching Protocols
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Accept: 1qVdfYHU9hPOl4JYYNXF623Gzn0=
Sec-WebSocket-Protocol: v10.stomp</code>

After a successful handshake, the TCP socket remains open and both client and server can continue to send and receive messages.

If the WebSocket server sits behind a web server such as Nginx, additional configuration may be required to forward the Upgrade request.

HTTP vs. WebSocket

Although WebSocket starts with an HTTP request, its architecture and programming model differ greatly from traditional HTTP/REST. HTTP models multiple URLs with request‑response semantics, while WebSocket typically uses a single URL and a persistent, event‑driven, asynchronous message flow.

WebSocket is a transport protocol without built‑in message semantics; applications must agree on a higher‑level protocol (e.g., STOMP) via the Sec-WebSocket-Protocol header.

When to Use WebSocket

WebSocket adds dynamic, interactive capabilities to web pages, but for many scenarios Ajax, HTTP streaming, or long polling are sufficient. Real‑time collaboration, gaming, and financial applications benefit most from low latency, high‑frequency, high‑throughput communication.

Network proxies and firewalls may block Upgrade headers, making WebSocket more suitable for internal services than public‑facing ones.

Core WebSocket API in Spring

Spring provides a WebSocket API for building client and server applications.

WebSocketHandler

Implement WebSocketHandler or extend TextWebSocketHandler / BinaryWebSocketHandler . Example using TextWebSocketHandler :

<code>public class MessageHandler extends TextWebSocketHandler {

    @Override
    public void handleTextMessage(WebSocketSession session, TextMessage message) {
        System.out.printf("SessionId: %s, Received: %s%n", session.getId(), message.getPayload());
        try {
            session.sendMessage(new TextMessage("Server received - " + message.getPayload()));
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    @Override
    public void afterConnectionEstablished(WebSocketSession session) throws Exception {
        System.out.printf("Connection established, SessionId: %s, Attributes: %s%n", session.getId(), session.getAttributes());
    }

    @Override
    public void afterConnectionClosed(WebSocketSession session, CloseStatus status) throws Exception {
        System.out.printf("Connection closed, SessionId: %s, Status: %s%n", session.getId(),
                status.getCode() + " - " + status.getReason());
    }
}
</code>

WebSocket configuration:

<code>@Configuration
@EnableWebSocket
public class WebSocketConfig implements WebSocketConfigurer {

    @Override
    public void registerWebSocketHandlers(WebSocketHandlerRegistry registry) {
        registry.addHandler(messageHandler(), "/message");
    }

    @Bean
    public WebSocketHandler messageHandler() {
        return new MessageHandler();
    }
}
</code>

To customize the handshake, implement a HandshakeInterceptor . Example:

<code>@Configuration
@EnableWebSocket
public class WebSocketConfig implements WebSocketConfigurer {

    @Override
    public void registerWebSocketHandlers(WebSocketHandlerRegistry registry) {
        registry.addHandler(messageHandler(), "/message")
                .setHandshakeHandler(handshakeHandler())
                .addInterceptors(new HandshakeInterceptor() {
                    @Override
                    public boolean beforeHandshake(ServerHttpRequest request, ServerHttpResponse response,
                                                   WebSocketHandler wsHandler, Map<String, Object> attributes) throws Exception {
                        attributes.put("uid", uid);
                        return true;
                    }

                    @Override
                    public void afterHandshake(ServerHttpRequest request, ServerHttpResponse response,
                                               WebSocketHandler wsHandler, Exception exception) {
                        // post‑handshake logic
                    }
                });
    }
}
</code>

Spring WebSocket integrates easily with Spring MVC; the DispatcherServlet can handle both HTTP requests and WebSocket handshakes. For JSR‑356 runtimes, specific RequestUpgradeStrategy implementations are required for servers such as Tomcat, Jetty, GlassFish, WebLogic, WebSphere, Undertow, and WildFly.

Each underlying WebSocket engine exposes configuration properties (e.g., message buffer size, idle timeout). Example for Tomcat/GlassFish:

<code>@Bean
public ServletServerContainerFactoryBean servletServerContainerFactoryBean() {
    ServletServerContainerFactoryBean container = new ServletServerContainerFactoryBean();
    container.setMaxTextMessageBufferSize(8192);
    container.setMaxBinaryMessageBufferSize(8192);
    return container;
}
</code>

Since Spring Framework 4.1.5, WebSocket and SockJS default to same‑origin requests. You can allow all origins with:

<code>@Configuration
@EnableWebSocket
public class WebSocketConfig implements WebSocketConfigurer {

    @Override
    public void registerWebSocketHandlers(WebSocketHandlerRegistry registry) {
        registry.addHandler(messageHandler(), "/message")
                .setAllowedOriginPatterns("*");
    }
}
</code>

Testing

After configuring the environment, you can test the WebSocket endpoint with Postman. Successful connection, message sending, and server receipt are shown in the screenshots below.

Javareal-time messagingBackend DevelopmentSpring Bootwebsocket
Spring Full-Stack Practical Cases
Written by

Spring Full-Stack Practical Cases

Full-stack Java development with Vue 2/3 front-end suite; hands-on examples and source code analysis for Spring, Spring Boot 2/3, and Spring Cloud.

0 followers
Reader feedback

How this landed with the community

login Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.