Fermer

février 27, 2024

Comment utiliser les événements envoyés par le serveur dans Node.js —

Comment utiliser les événements envoyés par le serveur dans Node.js —


Dans cet article, nous verrons comment utiliser les événements envoyés par le serveur pour permettre à un client de recevoir des mises à jour automatiques d’un serveur via une connexion HTTP. Nous verrons également pourquoi cela est utile et nous montrerons des démonstrations pratiques sur la façon d’utiliser les événements envoyés par le serveur avec Node.js.

Table des matières

Pourquoi les événements envoyés par le serveur sont utiles

Le Web est basé sur des messages HTTP requête-réponse. Votre navigateur effectue une demande d’URL et un serveur répond avec des données. Cela peut entraîner d’autres requêtes du navigateur et des réponses du serveur pour les images, CSS, JavaScript, etc. Le serveur ne peut pas lancer messages au navigateur, alors comment peut-il indiquer que les données ont changé ? Heureusement, vous pouvez ajouter des fonctionnalités telles que des bulletins d’information en direct, des bulletins météorologiques et des cours boursiers avec des événements envoyés par le serveur.

La mise en œuvre de mises à jour de données en direct à l’aide des technologies Web standards a toujours été possible :

  • Le Web des années 1990 utilisait une actualisation pleine page ou frame/iframe.
  • Le Web des années 2000 a introduit Ajax, qui pouvait utiliser de longues interrogations pour demander des données et mettre à jour les éléments DOM appropriés avec de nouvelles informations.

Aucune des deux options n’est idéale, puisque le navigateur doit déclencher une actualisation. S’il effectue des requêtes trop souvent, aucune donnée n’aura changé et le navigateur et le serveur effectueront un travail inutile. S’il effectue des requêtes trop lentement, il risque de manquer une mise à jour importante et le cours de l’action que vous surveillez s’est déjà effondré !

Événements envoyés par le serveur (SSE) permettent à un serveur de transmettre des données au navigateur à tout moment :

  • Le navigateur effectue toujours la demande initiale pour établir une connexion.
  • Le serveur renvoie une réponse de flux d’événements et maintient la connexion ouverte.
  • Le serveur peut utiliser cette connexion pour envoyer des messages texte à tout moment.
  • Les données entrantes déclenchent un événement JavaScript dans le navigateur. Une fonction de gestionnaire d’événements peut analyser les données et mettre à jour le DOM.

Essentiellement, SSE est un flux incessant de données. Considérez-le comme le téléchargement d’un fichier infiniment volumineux en petits morceaux que vous pouvez intercepter et lire.

SSE a été implémenté pour la première fois en 2006 et tous les principaux navigateurs prennent en charge la norme. Il est peut-être moins connu que WebSockets, mais les événements envoyés par le serveur sont plus simples, utilisent le HTTP standard, prennent en charge la communication unidirectionnelle et offrent une reconnexion automatique. Ce didacticiel fournit un exemple de code Node.js sans modules tiers, mais SSE est disponible dans d’autres langages côté serveur. y compris PHP.

Démarrage rapide des événements envoyés par le serveur

La démonstration suivante implémente un serveur Web Node.js qui génère un nombre aléatoire compris entre 1 et 1 000 à un intervalle aléatoire d’au moins une fois toutes les trois secondes.

Ci-dessous notre démonstration Node.js SSE (vous pouvez ouvrez-le dans un onglet de navigateur séparé si tu préfères).

Le code utilise le standard Node.js http et url modules de création d’un serveur web et d’analyse des URL :

import http from "node:http";
import url from "node:url";

Le serveur examine la requête URL entrante et réagit lorsqu’il rencontre un /random chemin:

const port = 8000;

http.createServer(async (req, res) => {

  
  const uri = url.parse(req.url).pathname;

  
  switch (uri) {
    case "/random":
      sseStart(res);
      sseRandom(res);
      break;
  }

}).listen(port);

console.log(`server running: http://localhost:${port}\n\n`);

Il répond initialement avec l’en-tête de flux d’événements HTTP SSE :


function sseStart(res) {
  res.writeHead(200, {
    Content-Type: "text/event-stream",
    Cache-Control: "no-cache",
    Connection: "keep-alive"
  });
}

Une autre fonction envoie alors un nombre aléatoire et s’appelle après un intervalle aléatoire :


function sseRandom(res) {
  res.write("data: " + (Math.floor(Math.random() * 1000) + 1) + "\n\n");
  setTimeout(() => sseRandom(res), Math.random() * 3000);
}

Si vous exécutez le code localement, vous pouvez tester la réponse en utilisant boucle dans votre terminal :

$> curl -H Accept:text/event-stream http://localhost:8000/random
data: 481

data: 127

data: 975

Presse Ctrl | Commande et C pour mettre fin à la demande.

Le JavaScript côté client du navigateur se connecte au /random URI utilisant un Constructeur d’objet EventSource:


const source = new EventSource("/random");

Les données entrantes déclenchent un message gestionnaire d’événements où la chaîne qui suit data: est disponible dans l’objet événement .data propriété:

source.addEventListener('message', e => {
  console.log('RECEIVED', e.data);
});

Notes IMPORTANTES

  • Comme Aller chercher()le navigateur effectue une requête HTTP standard, vous devrez donc peut-être gérer Fournisseur de services de chiffrement, CORS et éventuellement passer une seconde { withCredentials: true } argument à la EventSource constructeur pour envoyer des cookies.
  • Le serveur doit conserver les individus res des objets de réponse pour chaque utilisateur connecté afin de lui envoyer des données. Ceci est réalisé dans le code ci-dessus en transmettant la valeur dans une fermeture au prochain appel.
  • Les données du message ne peuvent être qu’une chaîne (peut-être JSON) envoyée au format data: <message>\n\n. Les retours chariot de fin sont indispensables.
  • Le serveur peut mettre fin à une réponse SSE à tout moment avec res.end()mais…
  • Lorsqu’une déconnexion se produit, le navigateur tente automatiquement de se reconnecter ; il n’est pas nécessaire d’écrire votre propre code de reconnexion.

Événements avancés envoyés par le serveur

SSE ne nécessite pas plus de code que celui indiqué ci-dessus, mais les sections suivantes traitent d’autres options.

Un ou plusieurs canaux SSE

Un serveur peut fournir n’importe quel nombre d’URL de canaux SSE. Par exemple:

  • /latest/news
  • /latest/weather
  • /latest/stockprice

Cela peut être pratique si une seule page affiche un sujet, mais moins si une seule page affiche les actualités, la météo et les cours des actions. Dans cette situation, le serveur doit maintenir trois connexions pour chaque utilisateur, ce qui pourrait entraîner des problèmes de mémoire à mesure que le trafic augmente.

Une autre option consiste à fournir une URL de point de terminaison unique, telle que /latest, qui envoie n’importe quel type de données sur un seul canal de communication. Le navigateur peut indiquer les sujets d’intérêt dans la chaîne de requête URL, par exemple : /latest?type=news,weather,stockprice – afin que le serveur puisse limiter les réponses SSE à des messages spécifiques.

Envoi de différentes données sur un seul canal

Les messages du serveur peuvent avoir un associé event: passé sur la ligne au-dessus du data: pour identifier des types spécifiques d’informations :

event: news
data: SSE is great!

event: weather
data: { "temperature": "20C", "wind": "10Kph", "rain": "25%" }

event: stock
data: { "symbol": "AC", "company": "Acme Corp", "price": 123.45, "increase": -1.1 }

Ceux-ci seront pas déclencher le côté client "message" gestionnaire d’événements. Vous devez ajouter des gestionnaires pour chaque type de event. Par exemple:


source.addEventListener('news', e => {

  document.getElementById('headline')
    .textContent = e.data;

});


source.addEventListener('weather', e => {

  const w = JSON.parse(e.data);

  document.getElementById('weather')
    .textContent = `${ w.temperature } with ${ w.wind } wind`;

});


source.addEventListener('stock', e => {

  const s = JSON.parse(e.data);

  document.getElementById(`stock-${ s.symbol }`)
    .textContent = `${ s.share }: ${ s.price } (${ s.increase }%)`;

});

Utiliser des identifiants de données

En option, le serveur peut également envoyer un id: après un data: doubler:

event: news
data: SSE is great!
id: 42

Si la connexion est interrompue, le navigateur envoie le dernier id retour au serveur dans le Last-Event-ID En-tête HTTP afin que le serveur puisse renvoyer tous les messages manqués.

L’ID le plus récent est également disponible côté client dans le fichier de l’objet événement. .lastEventId propriété:


source.addEventListener('news', e => {

  console.log(`last ID: ${ e.lastEventId }`);

  document.getElementById('headline')
    .textContent = e.data;

});

Spécification des délais de nouvelle tentative

Bien que la reconnexion soit automatique, votre serveur peut savoir que de nouvelles données ne sont pas attendues avant une période spécifique, il n’est donc pas nécessaire de conserver un canal de communication actif. Le serveur peut envoyer un retry: réponse avec une valeur en millisecondes, seule ou dans le cadre d’un message final. Par exemple:

retry: 60000
data: Please don't reconnect for another minute!

Dès réception, le navigateur abandonnera la connexion SSE et tentera de se reconnecter une fois le délai écoulé.

Autres gestionnaires d’événements

Ainsi que "message" et des événements nommés, vous pouvez également créer "open" et "error" gestionnaires dans votre JavaScript côté client.

Un "open" L’événement se déclenche lorsque la connexion au serveur est établie. Il peut être utilisé pour exécuter du code de configuration supplémentaire ou initialiser des éléments DOM :

const source = new EventSource('/sse1');

source.addEventListener('open', e => {

  console.log('SSE connection established.');

});

Un "error" L’événement se déclenche lorsque la connexion au serveur échoue ou se termine. Vous pouvez examiner l’objet événement .eventPhase propriété pour vérifier ce qui s’est passé :

source.addEventListener('error', e => {

    if (e.eventPhase === EventSource.CLOSED) {
      console.log('SSE connection closed');
    }
    else {
      console.log('error', e);
    }

});

N’oubliez pas qu’il n’est pas nécessaire de vous reconnecter : cela se produit automatiquement.

Terminer la communication SSE

Le navigateur peut mettre fin à une communication SSE à l’aide de l’objet EventSource .close() méthode. Par exemple:

const source = new EventSource('/sse1');


setTimeout(() => source.close(), 3_600_000);

Le serveur peut mettre fin à la connexion en :

  1. cuisson res.end() ou envoyer un retry: retardalors
  2. renvoyant un statut HTTP 204 lorsque le même navigateur tente de se reconnecter.

Seul le navigateur peut rétablir une connexion en créant un nouveau EventSource objet.

Conclusion

Les événements côté serveur fournissent un moyen d’implémenter des mises à jour de pages en direct qui sont peut-être plus faciles, plus pratiques et plus légères que Fetch()-sondage Ajax basé sur. La complexité réside du côté du serveur. Vous devez:

  1. conserver toutes les connexions actives de l’utilisateur en mémoire, et
  2. déclencher des transmissions de données lorsque quelque chose change.

Mais cela est entièrement sous votre contrôle et la mise à l’échelle ne devrait pas être plus complexe que n’importe quelle autre application Web.

Le seul inconvénient est que SSE ne permet pas d’envoyer des messages du navigateur vers le serveur (en dehors de la demande de connexion initiale). Vous pouvez utiliser Ajax, mais c’est trop lent pour des applications telles que les jeux d’action. Pour une bonne communication bidirectionnelle, vous avez besoin de WebSockets. Nous aurons bientôt un nouveau tutoriel à ce sujet !




Source link