In today’s text, I want to take a closer look at Server Sent Events (or SSE for short) and WebSockets. Both are good and battle-tested approaches to data exchange.
I will start with a short characteristic of both tools – what they are and what they offer. Then, I will compare them according to eight categories, which, in my opinion, are the most crucial for modern-day systems.
The categories are as follows:
- Communication Direction
- Underlying Protocol
- Security
- Simplicity
- Performance
- Message Structure
- Ease of Adoption
- Tooling
In contrast to my previous comparison, which compared REST and qRPC I will not proclaim any winner or grant points per category. Instead, in the Summary paragraph, you will find a kind of TL;DR table. The table contains the key differences between both technologies in the above-mentioned areas.
The Why?
Unlike REST, both SSE and WebSockets are more use-case-focused. In this particular case (or cases), the main focus point of both concepts is providing a “real-time” communication medium. Because of their specific focus, they are less popular than REST, which is a more generic and one-size-fits-all type of tool.
Nevertheless, both SSE and WebSockets offer an interesting set of possibilities and a slight refreshment from the classic REST approach to solving problems.
In my opinion, it is good to be aware of them and find some space for them in our toolbox, as they may come in handy one day. Providing you with a simpler solution to quite a complex problem. Especially when you will need “real-time” updates or when your app will require a more push oriented approach.
Besides comparing and describing them here, I also want to make them more popular.
What is WebSockets?
In short, it is a communication protocol that provides bi-directional communication between server and client with the usage of a single long-lasting TCP connection. Thanks to this feature, we do not have to constantly pull new data from the server. Instead, the data is exchanged between interested parties in “real-time”. Each message is either binary data or Unicode text.
The protocol was standardized in 2011 by the IETF in the form of RFC 6455. WebSocket protocol is distinct from HTTP, but both are located at layer 7 of the OSI model and depend on TCP at the 4th layer.
The protocol has its unique set of prefixes, which works in a similar manner as HTTP prefixes of http and https:
- ws -> indicates that the connection is not secured with TLS
- wss -> indicate that the connection is secured with TLS
What is more, non-secure WebSockets connections (ws) should not be open from secure sites (https). Similarly, secure WebSockets connections (wss) should not be open from non-secure sites (http).
On the other hand, WebSocket, by design, works on HTTP ports 443 and 80 and supports HTTP concepts like proxies and intermediaries. What is more, WebSocket handshake uses an HTTP upgrade header to upgrade protocol from HTTP to WebSocket.
The biggest disadvantage of WebSocket as a protocol is security. WebSocket is not restricted by same-origin policy, which may make CSRF-like attacks a lot easier.
What is Server Sent Events?
SSE is a technology that allows a web server to send updates to a web page. It is a part of HTML 5 specification and similarly to WebSockets utilizes a single long live HTTP connection to send data in “real-time”. On a conceptual level, it is quite old technology with its theoretical background dating back to 2004. The first approach to implementing SSE was conducted in 2006 by the Opera team.
SSE is supported by most of the modern day browsers – Microsoft Edge added SSE support in January 2020. It can also take full advantage of HTTP/2, which eliminates one of the biggest issues of SSE, by practically eliminating the connection limit imposed by HTTP/1.1.
By definition Server Sent Events have two basic building blocks:
- EventSource -> interface based on WHATWG specification and implemented by the browser, it allows the client (a browser in this case) to subscribe to events.
- Event stream -> protocol that describes the standard plain-text format of events sent by the server must follow for the EventSource client to understand and propagate them.
According to the specification, events can carry arbitrary text data, an optional ID, and are delimited by newlines. They even have their unique MIME type: text/event-stream
.
Unfortunately, the Server Sent Events as a technology is designed to support only text-based messages and although we can send events with custom format in the end the message must be a UTF-8 encoded string.
What is more, SSE provides two very interesting features:
- Automatic reconnection -> If the client disconnects unexpectedly EventSource periodically tries to reconnect.
- Automatic stream resume -> EventSource automatically remembers the last received message ID and will automatically send a Last-Event-ID header when trying to reconnect.
WebSockets vs SSE
Communication Direction
Probably the biggest difference between the two is their way of communication.
- SSE provides only one-way communication – events can only be sent from the server to the client.
- WebSockets provides full two-way communication, enabling interested parties to exchange information and react to any events from both sides.
I would say that both of the approaches have their pros and cons with a set of dedicated use cases for each.
On one hand, if you just need to push a stream of constant updates to the client, then SSE would be a more suitable choice. On the other hand, if you need to react in any way to one of those events, then WebSocket may be more beneficial.
In theory (and practice), all the things that can be done with SSE can also be done with WebSockets, but then we are entering areas like support, simplicity of the solution, or security.
I will describe all of these areas and more in the following paragraphs. What is more, using WebSocket in all the cases can be a significant overkill, and an SSE-based solution may just be simpler to implement.
Underlying Protocol
Here comes another big difference between both technologies.
- SSE fully relies on HTTP and has support for both HTTP/1.1 and HTTP/2.
- In contrast, WebSocket is using its own custom protocol, surprise, surprise – the WebSocket protocol.
In the case of SSE, utilizing HTTP/2 solves one of the major issues of SSE – max parallel connection limit. The HTTP/1.1, by its specification, limits the number of parallel connections.
This behavior may lead to a problem called head-of-line blocking. HTTP/2 addresses this issue via the introduction of multiplexing, which solves HOL blocking at the application layer. However, head-of-line blocking may still occur on the TCP level.
As to WebSocket protocol, I mentioned it in some detail, just a few lines above. Here, I would just reiterate the most important points. The protocol is somewhat different from classic HTTP despite using an HTTP upgrade header to initialize the WebSocket connection and effectively change communication protocols.
Nevertheless, it is also using TCP protocol as a base and is fully compatible with HTTP. The biggest drawback of the WebSocket protocol is its security.
Simplicity
In general, setting up SSE-based integration is simpler than its WebSocket counterpart. The most important reason behind it is the nature of communication utilized by a particular technology.
One-directional way of SSE and its push model makes it easier on a conceptual level. Combining it with the automatic reconnection and stream continuity support provided out of the box the number of things that we have to take care of is significantly reduced.
With all of these features, SSE may also be viewed as a way to reduce the coupling between client and server. Clients just need to know an endpoint that produces the events.
Nevertheless, in such a case, the client can only receive messages, so if we want to send any type of information back to the server, we need to have another communication medium, which may greatly complicate things.
In the case of WebSocket, things are somewhat more complicated. First of all, we need to handle the connection upgrade from HTTP to WebSocket protocol. Albeit being the simplest thing here, it is another thing we need to remember.
The second problem comes from the bi-directional nature of WebSockets. We have to manage the state of a particular connection and handle all possible exceptions occurring while processing the message. For example, what if the processing of one of the messages will throw an exception on the server side?
Next comes the problem of handling reconnections, which, in the case of WebSockets, we have to handle ourselves.
There is also a problem that impacts both technologies – long-running connections.
Both technologies need to maintain long-lived open connections to send a continuous stream of events.
Managing such connections, especially on a large scale, can be a challenge as we can quite quickly run out of resources. Additionally, they may require special configurations like extended timeout and are more exposed to any network connection problems.
Security
In the case of SSE, there is nothing special about security as it utilizes the plain old HTTP protocol as the transport medium. All standard HTTP advantages and disadvantages apply to SSE, as simple as that.
On the other hand, security is one of the biggest drawbacks of WebSocket protocol as a whole. For a start, there is no such thing as Same Origin Policy, so there are no restrictions as to the place that we want to connect via WebSockets.
There is even a specific type of attack aimed at exploiting this vulnerability, the Cross-Origin WebSocket Hijacking. If you want to dive more into the topic of Same Origin Policy and WebSocket, here is the article that can be interesting for you. Besides that, there are no protocol-specific security loopholes in WebSockets.
I would say that in both cases, all the standards and best security practices apply, so just be careful while you are implementing your solution.
Performance
I would say that both of the technologies are on equal footing as to the performance. No theoretical performance limitations are coming from either of the technologies themselves.
However, I would say that SSE can be faster in terms of a pure number of messages sent per second as it kind of works on fire and forget principle. WebSocket needs to also handle responses coming from the client.
The only thing that can impact the performance of both of them is the underlying client we are using in our application and its implementation. Check, read documentation, run custom stress tests, and you may end up with very interesting insight about the tool you are using or your entire system.
Message Structure
The message structure is probably another one of the most important differences between protocols.
As I mentioned above, SSE is a pure text protocol. We can send messages with different formats and contents, but in the end, everything ends up as UTF-8 encoded text. No complex format or binary data is possible.
WebSocket, on the other hand, can handle both text and binary messages. Giving us the possibility to send images, audio, or just regular files. Just remember that processing files can have a significant overhead.
Ease of Adoption
Here, both of the technologies are on a very similar stage. There are plenty of tools for adding WebSockets and Server Sent Events support, both client and server, from an SSE perspective.
Most of the established programming languages have more than one such library. Without going into too much detail. I have prepared the table summarizing the basic libraries, adding WebSockets and SSE support.
Language | Server Sent Events | WebSockets |
---|---|---|
Java | Spring (SSE), Quarkus (SSE) | Spring (WebSockets), Quarkus (WebSockets) |
Scala | Akka (SSE), Play (SSE) | Akka (WebSockets), Play (WebSockets) |
JavaScript | EventSource, total.js (SSE) | Socket.io, total.js (WebSocekts) |
Python | Starlette | FastAPI |
As you can see, we have plenty of well-established choices if we want to add SEE or WebSockets integration to our application. Of course, this is only a minuscule example picked from all of the libraries, there are many more out there. The real problem may be finding the one most suitable for your particular use case.
Tooling
Automated Tests
As far as I know, there are no automated testing tools for either SSE or WebSockets. However, you can relatively easily achieve similar functions with the use of Postman and collections.
Postman supports both Server Sent Events and WebSockets. With the use of some magic originating from Postman collections, you can prepare a set of tests verifying the correctness of your endpoints.
Performance Tests
In the case of Performance Tests, you can go with either JMeter or Gatling. As far as I am aware, these are the two most mature tools for overall performance testing. Of course, both of them also support SSE (JMeter, Gatling) and WebSockets (JMeter, Gatling).
There are also other tools like sse-perf (SSE only), Testable or k6 (WebSockets only).
Out of all of these tools, I would personally recommend Gatling or k6. Both seem to have the best user experience and be the most production ready.
Documentation
To a degree, there are no tools dedicated solely to documenting either SSE or WebSockets. On the other hand, there is a tool called AsyncAPI which can be used just in this way for both concepts.
Unfortunately OpenAPI seems not to support either SSE or WebSockets.
Summary
As I promised, the summary will be quick and simple – look below.
I think that the table above is quite a nice and compact summary of the topic and the article as a whole.
The most important difference is the Communication Direction as it determines the possible use case of a particular technology. It will probably have the biggest impact on choosing one over the other.
Message structure can also be a very important category when it comes to choosing a particular way of communication. Allowing only plain text messages is a very significant drawback for Server Sent Events.
Thank you for your time.
Comments are closed.