REST vs WebSockets

1. Vue d'ensemble

Dans ce didacticiel, nous allons passer en revue les bases de la communication client-serveur et explorer cela à travers deux options populaires disponibles aujourd'hui. Nous verrons comment WebSocket, qui est un nouvel entrant, se compare au choix plus populaire de RESTful HTTP.

2. Bases de la communication réseau

Avant de plonger dans les détails des différentes options et de leurs avantages et inconvénients, rafraîchissons rapidement le paysage de la communication réseau. Cela aidera à mettre les choses en perspective et à mieux comprendre cela.

Les communications réseau peuvent être mieux comprises en termes de modèle d'interconnexion des systèmes ouverts (OSI).

Le modèle OSI divise le système de communication en sept couches d'abstraction:

En haut de ce modèle se trouve la couche Application qui nous intéresse dans ce tutoriel. Cependant, nous discuterons de certains aspects des quatre couches supérieures au fur et à mesure que nous comparons WebSocket et RESTful HTTP.

La couche application est la plus proche de l'utilisateur final et est responsable de l'interfaçage avec les applications participant à la communication. Il existe plusieurs protocoles populaires utilisés dans cette couche, tels que FTP, SMTP, SNMP, HTTP et WebSocket.

3. Décrire WebSocket et HTTP RESTful

Bien que la communication puisse avoir lieu entre n'importe quel nombre de systèmes, nous sommes particulièrement intéressés par la communication client-serveur. Plus précisément, nous nous concentrerons sur la communication entre un navigateur Web et un serveur Web. C'est le cadre que nous utiliserons pour comparer WebSocket avec RESTful HTTP.

Mais avant d'aller plus loin, pourquoi ne pas comprendre rapidement ce qu'ils sont!

3.1. WebSockets

Selon la définition formelle, WebSocket est un protocole de communication qui propose une communication bidirectionnelle en duplex intégral sur une connexion TCP persistante. Maintenant, nous allons comprendre chaque partie de cette déclaration en détail au fur et à mesure.

WebSocket a été normalisé en tant que protocole de communication par l'IETF sous le nom de RFC 6455 en 2011. La plupart des navigateurs Web modernes prennent aujourd'hui en charge le protocole WebSocket.

3.2. HTTP RESTful

Bien que nous connaissions tous HTTP en raison de sa présence omniprésente sur Internet, il s'agit également d'un protocole de communication de couche application. HTTP est un protocole basé sur une requête-réponse , encore une fois, nous le comprendrons mieux plus tard dans le didacticiel.

REST (Representational State Transfer) est un style architectural qui met un ensemble de contraintes sur HTTP pour créer des services Web.

4. Sous-protocole WebSocket

Alors que WebSocket définit un protocole de communication bidirectionnelle entre client et serveur, il ne met aucune condition sur le message à échanger . Ceci est laissé libre aux parties dans la communication de s'entendre dans le cadre de la négociation du sous-protocole.

Il n'est pas pratique de développer un sous-protocole pour des applications non triviales. Heureusement, il existe de nombreux sous-protocoles populaires comme STOMP . STOMP signifie Simple Text Oriented Messaging Protocol et fonctionne sur WebSocket. Spring Boot a un support de première classe pour STOMP, que nous utiliserons dans notre tutoriel.

5. Configuration rapide dans Spring Boot

Il n'y a rien de mieux que de voir un exemple fonctionnel. Nous allons donc créer des cas d'utilisation simples à la fois dans WebSocket et RESTful HTTP pour les explorer plus avant et les comparer. Créons un simple serveur et un composant client pour les deux.

Nous allons créer un client simple en utilisant JavaScript qui enverra un nom. Et nous allons créer un serveur utilisant Java qui répondra par un message d'accueil.

5.1. WebSocket

Pour utiliser WebSocket dans Spring Boot, nous aurons besoin du démarreur approprié:

 org.springframework.boot spring-boot-starter-websocket 

Nous allons maintenant configurer les points de terminaison STOMP:

@Configuration @EnableWebSocketMessageBroker public class WebSocketMessageBrokerConfig implements WebSocketMessageBrokerConfigurer { @Override public void registerStompEndpoints(StompEndpointRegistry registry) { registry.addEndpoint("/ws"); } @Override public void configureMessageBroker(MessageBrokerRegistry config) { config.setApplicationDestinationPrefixes("/app"); config.enableSimpleBroker("/topic"); } }

Définissons rapidement un serveur WebSocket simple qui accepte un nom et répond par un message d'accueil:

@Controller public class WebSocketController { @MessageMapping("/hello") @SendTo("/topic/greetings") public Greeting greeting(Message message) throws Exception { return new Greeting("Hello, " + HtmlUtils.htmlEscape(message.getName()) + "!"); } }

Enfin, construisons le client pour communiquer avec ce serveur WebSocket. Alors que nous mettons l'accent sur la communication navigateur-serveur, créons un client en JavaScript:

var stompClient = null; function connect() { stompClient = Stomp.client('ws://localhost:8080/ws'); stompClient.connect({}, function (frame) { stompClient.subscribe('/topic/greetings', function (response) { showGreeting(JSON.parse(response.body).content); }); }); } function sendName() { stompClient.send("/app/hello", {}, JSON.stringify({'name': $("#name").val()})); } function showGreeting(message) { $("#greetings").append("" + message + ""); }

Ceci complète notre exemple de travail d'un serveur et d'un client WebSocket. Il existe une page HTML dans le référentiel de code qui fournit une interface utilisateur simple avec laquelle interagir.

Bien que cela ne fasse qu'effleurer la surface, WebSocket avec Spring peut être utilisé pour créer des clients de discussion complexes et plus encore.

5.2. HTTP RESTful

Nous allons maintenant passer par une configuration similaire pour le service RESTful. Notre service Web simple acceptera une demande GET avec un nom et répondra par un message d'accueil.

Utilisons plutôt le web starter de Spring Boot cette fois:

 org.springframework.boot spring-boot-starter-web 

Nous allons maintenant définir un point de terminaison REST en tirant parti de la puissante prise en charge des annotations disponible dans Spring:

@RestController @RequestMapping(path = "/rest") public class RestAPIController { @GetMapping(path="/{name}", produces = "application/json") public String getGreeting(@PathVariable("name") String name) { return "{\"greeting\" : \"Hello, " + name + "!\"}"; } }

Enfin, créons un client en JavaScript:

var request = new XMLHttpRequest() function sendName() { request.open('GET', '//localhost:8080/rest/'+$("#name").val(), true) request.onload = function () { var data = JSON.parse(this.response) showGreeting(data.greeting) } request.send() } function showGreeting(message) { $("#greetings").append("" + message + ""); }

C'est à peu près tout! Encore une fois, il existe une page HTML dans le référentiel de code pour fonctionner avec une interface utilisateur.

Bien que profonde dans sa simplicité, définir une API REST de qualité production peut être une tâche beaucoup plus étendue!

6. Comparaison de WebSocket et RESTful HTTP

Après avoir créé des exemples minimaux, mais fonctionnels, de WebSocket et de HTTP RESTful, nous sommes maintenant prêts à comprendre comment ils se comparent. Nous examinerons cela par rapport à plusieurs critères dans les sous-sections suivantes.

Il est important de noter que bien que nous puissions comparer directement HTTP et WebSocket car ce sont tous deux des protocoles de couche application, il n'est pas naturel de comparer REST à WebSocket . Comme nous l'avons vu précédemment, REST est un style architectural qui exploite HTTP pour la communication.

Par conséquent, notre comparaison avec WebSocket concernera principalement les capacités, ou leur absence, dans HTTP .

6.1. Schéma d'URL

Une URL définit l'emplacement unique d'une ressource Web et le mécanisme pour la récupérer . Dans une communication client-serveur, le plus souvent, nous cherchons à obtenir des ressources statiques ou dynamiques via leur URL associée.

Nous connaissons tous le schéma d'URL HTTP:

//localhost:8080/rest

Le schéma d'URL WebSocket n'est pas très différent non plus:

ws://localhost:8080/ws

Au départ, la seule différence semble être les caractères avant les deux points, mais cela fait beaucoup d'abstraction ce qui se passe sous le capot. Explorons plus loin.

6.2. Poignée de main

La poignée de main fait référence à la manière automatique de négocier le protocole de communication entre les parties qui communiquent . HTTP est un protocole sans état et fonctionne dans un mécanisme de requête-réponse. A chaque requête HTTP, une connexion TCP est établie avec le serveur via le socket.

The client then waits until the server responds with the resource or an error. The next request from the client repeats everything as if the previous request never happened:

WebSocket works very differently compared to HTTP and starts with a handshake before actual communication.

Let's see what comprise a WebSocket handshake:

In case of WebSocket, the client initiates a Protocol Handshake request in HTTP and then waits until the server responds accepting an upgrade to WebSocket from HTTP.

Of course, since Protocol Handshake happens over HTTP, it follows the sequence from the previous diagram. But once the connection is established, from there on client and server switches over to WebSocket for further communication.

6.3. Connection

As we saw in the previous subsection, one stark difference between WebSocket and HTTP is that WebSocket works on a persistent TCP connection while HTTP creates a new TCP connection for every request.

Now obviously creating new TCP connection for every request is not very performant and HTTP has not been unaware of this. In fact, as part of HTTP/1.1, persistent connections were introduced to alleviate this shortcoming of HTTP.

Nevertheless, WebSocket has been designed from the ground up to work with persistent TCP connections.

6.4. Communication

The benefit of WebSocket over HTTP is a specific scenario that arises from the fact that the client can server can communicate in ways which were not possible with good old HTTP.

For instance, in HTTP, usually the client sends that request, and then the server responds with requested data. There is no generic way for the server to communicate with the client on its own. Of course, patterns and solutions have been devised to circumvent this like Server-Sent Events (SSE), but these were not completely natural.

With WebSocket, working over persistent TCP communication, it's possible for server and client both to send data independent of each other, and in fact, to many communicating parties! This is referred to as bi-directional communication.

Another interesting feature of WebSocket communication is that it's full-duplex. Now while this term may sound esoteric; it simply means that both server and client can send data simultaneously. Compare this with what happens in HTTP where the server has to wait until it receives the request in full before it can respond with data.

While the benefit of bi-directional and full-duplex communication may not be apparent immediately. we'll see some of the use-cases where they unlock some real power.

6.5. Security

Last but not least, both HTTP and WebSocket leverage the benefits of TLS for security. While HTTP offers https as part of their URL scheme to use this, WebSocket has wss as part of their URL scheme for the same effect.

So the secured version of URLs from the previous subsection should look like:

//localhost:443/rest wss://localhost:443/ws

Securing either a RESTful service or a WebSocket communication is a subject of much depth and can not be covered here. For now, let's just say that both are adequately supported in this regard.

6.6. Performance

We must understand that WebSocket is a stateful protocol where communication happens over a dedicated TCP connection. On the other hand, HTTP is inherently a stateless protocol. This has an impact on how these will perform with the load but that really depends on the use case.

Since communication over WebSocket happens over a reusable TCP connection, the overhead per message is lower compared to HTTP. Hence it can reach higher throughput per server. But there is a limit to which a single server can scale and that is where WebSocket has issues. It's not easy to horizontally scale applications with WebSockets.

This is where HTTP shines. With HTTP each new request can potentially land on any server. This implies that to increase overall throughput we can easily add more servers. This should potentially have no impact on the application running with HTTP.

Obviously an application may itself need state and session stickiness which can make it easier said than done.

7. Where Should We Use Them?

Now, we have seen enough of RESTful service over HTTP and simple communication over WebSocket to form our opinion around them. But where should we use what?

It's important to remember that while WebSocket has emerged out of shortcomings in HTTP, it's not, in fact, a replacement of HTTP. So they both have their place and their uses. Let's quickly understand how can we make a decision.

For the bulk of the scenario where occasional communication is required with the server like getting the record of an employee, it's still sensible to use REST service over HTTP/S. But for newer client-side applications like a stock-price application which requires real-time updates from the server, it's much convenient to leverage WebSocket.

Generalizing, WebSocket is more suitable for cases where a push-based and real-time communication defines the requirement more appropriately. Additionally, WebSocket works well for scenarios where a message needs to be pushed to multiple clients simultaneously. These are the cases where client and server communication over RESTful services will find it difficult if not prohibitive.

Néanmoins, l'utilisation des services WebSocket et RESTful sur HTTP doit être tirée des exigences. Comme il n'y a pas de balles argentées, nous ne pouvons pas nous attendre à en choisir une pour résoudre tous les problèmes. Par conséquent, nous devons utiliser notre sagesse associée à nos connaissances pour concevoir un modèle de communication efficace.

8. Conclusion

Dans ce didacticiel, nous avons passé en revue les bases de la communication réseau en mettant l'accent sur les protocoles de couche application HTTP et WebSocket. Nous avons vu quelques démonstrations rapides de WebSocket et de l'API RESTful sur HTTP dans Spring Boot.

Enfin, nous avons comparé les fonctionnalités des protocoles HTTP et WebSocket et avons brièvement discuté de l'utilisation de chacun.

Comme toujours, le code des exemples est disponible à l'adresse over sur GitHub.