With WebSockets, client and sever can upgrade their connection using a bidirectional communication, allowing not only sending requests from client to server but also from server to client.
A WebSocket interaction begins with an HTTP request that uses the HTTP Upgrade header to upgrade or, in this case, to switch to the WebSocket protocol. The following example shows such an interaction:
GET /spring-websocket-portfolio/portfolio HTTP/1.1
Host: localhost:8080
Upgrade: websocket //The upgrade header
Connection: Upgrade //Using the upgrade header
Sec-WebSocket-Key: Uc9l9TMkWGbHFD2qnFHltg==
Sec-WebSocket-Protocol: v10.stomp, v11.stomp
Sec-WebSocket-Version: 13
Origin: <http://localhost:8080>
Instead of the usual 200 status code, a server with WebSocket support returns output similar to the following:
HTTP/1.1 101 Switching Protocols //Protocol Switch
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Accept: 1qVdfYHU9hPOl4JYYNXF623Gzn0=
Sec-WebSocket-Protocol: v10.stomp
After a successful handshake, the TCP socket underlying the HTTP upgrade request remains open for both the client and the server to continue to send and receive messages.
First, we need to add additional dependencies. In the build.gradle file in the backend:
dependencies {
--snip--
implementation 'org.springframework.bootspring-boot-starter-websocket'
}
And in the frontend:
dependencies {
--snip--
implementation 'org.springframework.bootspring-boot-starter-websocket:2.6.3'
}
Note in the backend we don’t specify the version of WebSockets. This is because, unlike in the frontend, we should the spring boot plugin in the build file, which automatically handles the version of the dependencies.
The WebSockets protocol defines two types of messages (text and binary), but their content is undefined. The protocol defines a mechanism for client and server to negotiate a sub-protocol (that is, a higher-level messaging protocol) to use on top of WebSockets to define what kind of messages each can send, what the format is, the content of each message, and so on. The use of a sub-protocol is optional but, either way, the client and the server need to agree on some protocol that defines message content.
One of these type messages is STOMP. With it, Clients can use the SEND or SUBSCRIBE commands to send or subscribe for messages, along with a destination header that describes what the message is about and who should receive it. This enables a simple publish-subscribe mechanism that you can use to send messages through the broker to other connected clients or to send messages to the server to request that some work be performed.
The following example shows a client subscribing to receive stock quotes, which the server may emit periodically (for example, via a scheduled task that sends messages through a SimpMessagingTemplate to the broker):
SUBSCRIBE
id:sub-1
destination:/topic/price.stock.*
^@
The following example shows a client that sends a trade request, which the server can handle through an @MessageMapping method:
SEND
destination:/queue/trade
content-type:application/json
content-length:44
{"action":"BUY","ticker":"MMM","shares",44}^@