Real Time Web

le

Http est un protocole client-serveur. Son côté omniprésent en a fait le meilleur ami des firewalls. HTTP fonctionne partout, tout le temps. Quelques fois, des proxys malicieux d'entreprise affichent des pedobears à la place de la page espérée, mais globalement, ça fonctionne.

Le deuxième ami d'HTTP est curl. Cet outil en ligne de commande, qui se démène pour gérer une multitude de protocoles n'est connu que pour son implémentation de référence d'HTTP. Pour éviter des trolls infinis sur le choix de client HTTP, qui lui est infini (allez regarder ce qui se fait en Ruby, pour rigoler), les exemples d'API REST (et donc HTTP) se font en curl. Curl, lingua franca de l'HTTP. Même Chrome propose dans ses outils de dev "copier cette requête comme une commande curl".

HTTP a été conçu dans l'idée d'un serveur public contacté par un client potentiellement privé (inaccessible derrière un NAT). Dans les faits, il est inaccessible, seuls les fous se connectent directement sur internet, sans passer par un routeur.

Il n'est pas farfelu de vouloir amorcer une discussion depuis le serveur.

Il y a plusieurs niveaux de violence pour arriver à faire ça :

  • Le polling. Le client pose et repose la question en boucle, avec souvent un grand vide comme réponse. Violent, et on trouve ça sur les interfaces web de routeurs.
  • Le long polling. Le client pose une question, le serveur attend d'avoir une réponse, fais poireauter jusqu'au timeout, et on recommence. Un peu moins violent, mais quand même. Les vieux connaissent ça sous le nom de Comet ou de Bayeux. Il y a des astuces à base d'iframe pour pallier à l'absence de XHR (le X d'Ajax) ou des contraintes de cross domain.
  • EventSource. HTML5, le successeur de DHTML et Ajax, fait le ménage dans les bricolages existants. Eventsource fait partie des nouveautés. Le principe est simple, le client amorce la communication avec un classique GET et serveur laisse la connexion ouverte. La réponse se fait dans un flot, avec un formatage très simple. Le client, gentiment fourni par le navigateur, se charge de la reconnexion, du parsing, le javascript se contente de gérer les évènements levés. Cette simplicité a un cout. Il ne faut aucun cache ou buffer entre le serveur et le client, mais surtout, il faut un serveur capable de maintenir ouverte une multitude de connexions. Il faut ça pour le frontend, et le serveur d'application. Le seul choix raisonnable est d'utiliser une technologie asynchrone. Ça tombe bien, c'est super à la mode. PHP, Ruby On Rails et Django font un peu la tête. Curl gère bien l'eventsource.
  • WebSocket. L'arme ultime. La connexion, un simple GET est upgradé en socket, bidirectionnel. La norme a connu des tâtonnements, entrainant des latences cotées client et serveur. Il y a peu d'espoir qu'un firewall d'entreprise se laisse berner par l'upgrade. Même exigence qu'EventSource pour maintenir ouvert une palanquée de connexions, et les traiter. Aucun des serveurs classiques ne sait proxyfier de la websocket. Nginx commence à peine à le faire, Haproxy le promet, Apache, on oublie. Il existe Hipache, une approche pragmatique à base de Nodejs. Sinon, il faut se mettre en direct, avec du Go, de l'Erlang (avec CowBoy), du Tornado... ce genre de choses.

Hum, ça laisse comme une impression de confusion, tout ça. Entre les concepts nouveaux : sortir du pattern confortable de la question/réponse et les soucis de compatibilités, il y a un marché pour les boites noires, qui emballent tout ça, avec la promesse de ne pas faire mal. Socket.io est LA référence pour proposer une socket qui marche quelque soit le contexte, avec un fallback Flash. L'implémentation de référence est en node, mais il existe maintenant plein de clones. Sockjs est un challenger. Je ne suis pas sur que rajouter des couches de complexités sur quelque chose de deja complexe permette d'espérer un comportement prévisible et de pouvoir corriger quoi que ce soit.

J'ai une approche plus darwiniste centralisateur : le W3C propose des normes que la plupart des navigateurs implémentent, malheur aux autres. C'est assez pénible que IE10, bien plus fréquentable que son ancêtre IE6, gère les websockets, mais pas event-source. Il existe une rustine de polyfill.

La première étape est en fait savoir si on a besoin d'une communication bidirectionnelle (un chat, un pad, un jeu en ligne...) ou d'un simple pull (le serveur parle aux clients). Ensuite, il faut savoir qui sont les clients, un navigateur web ou un client REST? Comment vont se passer les tests unitaires?

La seconde étape est de savoir comment gérer un pattern évènementiel avec des technologies classiques? Il faut soit utiliser une variante asynchrone d'une technologie existante (tornado pour Python, Event Machine pour Ruby...) soit passer à quelque chose de moderne (nodejs, golang, erlang, scala...). Il est aussi possible d'utiliser un joker : un robot qui répète. D'un coté il gère les connections et écoute les évènements, de l'autre coté, il dispatch le travail dans des modes classiques et séquentiels. J'avais prototypé Chaussette, et Dodger.io mais il existe des choses beaucoup plus costaud, comme Nginx Push Stream. Ce genre de dispatch est un peu le Hello World des technos asynchrones, c'est même sympa à faire. De toute façon, le gros boitier qui fait tout n'existe pas. Chaussette ne fait que du socket.io et transforme les flux montant en requête http, Dodger est plus un exemple pédagogique pour voir que ça ne fait pas mal, Push Stream gère tous les protocoles, mais ne fait que du push. D'où le nom. Il faut envisager des solutions sur mesure, à base de thread léger ou de workers, Redis peut même être un buzzword sympa à caler. C'est aussi une occasion de s'intéresser à la programmation évènementielle.

Le code n'est pas complexe, il faut juste comprendre que l'exécution du code n'est pas entièrement séquentielle. Voici un exemple en python ou en go, ou en node. Les clients eventsources sont trés simples, et n'ont aucune obligation d'être asynchrone : request-eventsource, sans oublier que la cible principale reste le navigateur web.

Les Websockets vous font flipper? Dépéchez vous, WebRTC arrive à grand pas!


Partager cet article :