Skip to content

Server Sent Events #156

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Jan 18, 2020
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
192 changes: 96 additions & 96 deletions 5-network/12-server-sent-events/article.md
Original file line number Diff line number Diff line change
@@ -1,32 +1,32 @@
# Server Sent Events

The [Server-Sent Events](https://html.spec.whatwg.org/multipage/comms.html#the-eventsource-interface) specification describes a built-in class `EventSource`, that keeps connection with the server and allows to receive events from it.
La spécification [Server-Sent Events](https://html.spec.whatwg.org/multipage/comms.html#the-eventsource-interface) décrit une classe intégrée `EventSource`, qui maintient la connexion avec le serveur et permet de recevoir des événements de celui-ci.

Similar to `WebSocket`, the connection is persistent.
Similaire à `WebSocket`, la connexion est persistante.

But there are several important differences:
Mais il existe plusieurs différences importantes :

| `WebSocket` | `EventSource` |
|-------------|---------------|
| Bi-directional: both client and server can exchange messages | One-directional: only server sends data |
| Binary and text data | Only text |
| WebSocket protocol | Regular HTTP |
| `WebSocket` | `EventSource` |
|-------------------------------------------------------------------------|-----------------------------------------------------|
| Bi-directionnel : le client et le serveur peuvent échanger des messages | Unidirectionnel: seul le serveur envoie des données |
| Données binaires et texte | Texte uniquement |
| Protocol WebSocket | HTTP régulier |

`EventSource` is a less-powerful way of communicating with the server than `WebSocket`.
`EventSource` est un moyen de communication avec le serveur moins puissant que `WebSocket`.

Why should one ever use it?
Dans ce cas pourquoi devrait-on l'utiliser ?

The main reason: it's simpler. In many applications, the power of `WebSocket` is a little bit too much.
La raison principale : c'est plus simple. Dans de nombreuses applications, la puissance de `WebSocket` est un peu trop importante.

We need to receive a stream of data from server: maybe chat messages or market prices, or whatever. That's what `EventSource` is good at. Also it supports auto-reconnect, something we need to implement manually with `WebSocket`. Besides, it's a plain old HTTP, not a new protocol.
Nous devons recevoir un flux de données du serveur: peut-être des messages de chat ou des prix du marché, ou autre chose. C'est à cela qu'`EventSource` est bon. Il prend également en charge la reconnexion automatique, quelque chose que nous devons implémenter manuellement avec `WebSocket`. De plus, c'est un vieux HTTP simple, pas un nouveau protocole.

## Getting messages
## Recevoir des messages

To start receiving messages, we just need to create `new EventSource(url)`.
Pour commencer à recevoir des messages, il suffit de créer `new EventSource(url)`.

The browser will connect to `url` and keep the connection open, waiting for events.
Le navigateur se connectera à `url` et gardera la connexion ouverte, en attendant les événements.

The server should respond with status 200 and the header `Content-Type: text/event-stream`, then keep the connection and write messages into it in the special format, like this:
Le serveur doit répondre avec le statut 200 et l'en-tête `Content-Type: text/event-stream`, puis conserver la connexion et y écrire des messages au format spécial, comme ceci :

```
data: Message 1
Expand All @@ -37,93 +37,93 @@ data: Message 3
data: of two lines
```

- A message text goes after `data:`, the space after the colon is optional.
- Messages are delimited with double line breaks `\n\n`.
- To send a line break `\n`, we can immediately send one more `data:` (3rd message above).
- Un texte de message va après `data:`, l'espace après les deux points est facultatif.
- Les messages sont délimités par des doubles sauts de ligne `\n\n`.
- Pour envoyer un saut de ligne `\n`, nous pouvons immédiatement envoyer une autre `data:` (3e message ci-dessus).

In practice, complex messages are usually sent JSON-encoded. Line-breaks are encoded as `\n` within them, so multiline `data:` messages are not necessary.
En pratique, les messages complexes sont généralement envoyés au format JSON. Les sauts de ligne sont codés en tant que `\n`, donc les messages multilignes de `data:` ne sont pas nécessaires.

For instance:
Par exemple :

```js
data: {"user":"John","message":"First line*!*\n*/!* Second line"}
```

...So we can assume that one `data:` holds exactly one message.
… On peut donc supposer qu'une `data:` contient exactement un message.

For each such message, the `message` event is generated:
Pour chacun de ces messages, l'événement `message` est généré :

```js
let eventSource = new EventSource("/events/subscribe");

eventSource.onmessage = function(event) {
console.log("New message", event.data);
// will log 3 times for the data stream above
// se connectera 3 fois pour le flux de données ci-dessus
};

// or eventSource.addEventListener('message', ...)
```

### Cross-origin requests
### Requêtes Cross-origin

`EventSource` supports cross-origin requests, like `fetch` any other networking methods. We can use any URL:
`EventSource` prend en charge les requêtes cross-origin, comme `fetch` toute autre méthode de mise en réseau. Nous pouvons utiliser n'importe quelle URL :

```js
let source = new EventSource("https://another-site.com/events");
```

The remote server will get the `Origin` header and must respond with `Access-Control-Allow-Origin` to proceed.
Le serveur distant obtiendra l'en-tête `Origin` et doit répondre avec `Access-Control-Allow-Origin` pour continuer.

To pass credentials, we should set the additional option `withCredentials`, like this:
Pour transmettre les informations d'identification, nous devons définir l'option supplémentaire `withCredentials`, comme ceci :

```js
let source = new EventSource("https://another-site.com/events", {
withCredentials: true
});
```

Please see the chapter <info:fetch-crossorigin> for more details about cross-origin headers.
Veuillez consulter le chapitre <info:fetch-crossorigin> pour plus de détails sur les en-têtes cross-origin.


## Reconnection
## Reconnexion

Upon creation, `new EventSource` connects to the server, and if the connection is broken -- reconnects.
Lors de la création, `new EventSource` se connecte au serveur, et si la connexion est rompue -- se reconnecte.

That's very convenient, as we don't have to care about it.
C'est très pratique, car nous n'avons pas à nous en soucier.

There's a small delay between reconnections, a few seconds by default.
Il y a un petit délai entre les reconnexions, quelques secondes par défaut.

The server can set the recommended delay using `retry:` in response (in milliseconds):
Le serveur peut définir le délai recommandé en utilisant `retry:` en réponse (en millisecondes) :

```js
retry: 15000
data: Hello, I set the reconnection delay to 15 seconds
```

The `retry:` may come both together with some data, or as a standalone message.
Le `retry:` peut venir à la fois avec certaines données, ou en tant que message autonome.

The browser should wait that many milliseconds before reconnecting. Or longer, e.g. if the browser knows (from OS) that there's no network connection at the moment, it may wait until the connection appears, and then retry.
Le navigateur doit attendre autant de millisecondes avant de se reconnecter. Ou plus, par exemple si le navigateur sait (depuis le système d'exploitation) qu'il n'y a pas de connexion réseau pour le moment, il peut attendre que la connexion apparaisse, puis réessayer.

- If the server wants the browser to stop reconnecting, it should respond with HTTP status 204.
- If the browser wants to close the connection, it should call `eventSource.close()`:
- Si le serveur souhaite que le navigateur cesse de se reconnecter, il doit répondre avec l'état HTTP 204.
- Si le navigateur souhaite fermer la connexion, il doit appeler `eventSource.close()`:

```js
let eventSource = new EventSource(...);

eventSource.close();
```

Also, there will be no reconnection if the response has an incorrect `Content-Type` or its HTTP status differs from 301, 307, 200 and 204. In such cases the `"error"` event will be emitted, and the browser won't reconnect.
De plus, il n'y aura pas de reconnexion si la réponse a un `Content-Type` incorrect ou si son état HTTP diffère de 301, 307, 200 et 204. Dans de tels cas, l'événement `"error"` sera émis et le navigateur ne se reconnecte pas.

```smart
When a connection is finally closed, there's no way to "reopen" it. If we'd like to connect again, just create a new `EventSource`.
Lorsqu'une connexion est finalement fermée, il n'y a aucun moyen de la "rouvrir". Si nous souhaitons nous reconnecter, créez simplement un nouveau `EventSource`.
```

## Message id
## ID du message

When a connection breaks due to network problems, either side can't be sure which messages were received, and which weren't.
Lorsqu'une connexion est interrompue en raison de problèmes de réseau, les deux parties ne peuvent pas savoir quels messages ont été reçus et lesquels ne l'ont pas été.

To correctly resume the connection, each message should have an `id` field, like this:
Pour reprendre correctement la connexion, chaque message doit avoir un champ `id`, comme ceci :

```
data: Message 1
Expand All @@ -137,40 +137,40 @@ data: of two lines
id: 3
```

When a message with `id:` is received, the browser:
Lorsqu'un message avec `id:` est reçu, le navigateur :

- Sets the property `eventSource.lastEventId` to its value.
- Upon reconnection sends the header `Last-Event-ID` with that `id`, so that the server may re-send following messages.
- Définit la propriété `eventSource.lastEventId` sur sa valeur.
- Lors de la reconnexion, l'en-tête `Last-Event-ID` est envoyé avec cet `id`, afin que le serveur puisse renvoyer les messages suivants.

```smart header="Put `id:` after `data:`"
Please note: the `id` is appended below message `data` by the server, to ensure that `lastEventId` is updated after the message is received.
```smart header="Mettre `id:` après `data:`"
Veuillez noter : l'`id` est ajouté sous le message `data` par le serveur, pour s'assurer que `lastEventId` est mis à jour après la réception du message.
```

## Connection status: readyState
## État de connexion : readyState

The `EventSource` object has `readyState` property, that has one of three values:
L'objet `EventSource` a la propriété `readyState`, qui a l'une des trois valeurs :

```js no-beautify
EventSource.CONNECTING = 0; // connecting or reconnecting
EventSource.OPEN = 1; // connected
EventSource.CLOSED = 2; // connection closed
EventSource.CONNECTING = 0; // connexion ou reconnexion
EventSource.OPEN = 1; // connecté
EventSource.CLOSED = 2; // connexion fermée
```

When an object is created, or the connection is down, it's always `EventSource.CONNECTING` (equals `0`).
Lorsqu'un objet est créé ou que la connexion est interrompue, il s'agit toujours de `EventSource.CONNECTING` (égal à `0`).

We can query this property to know the state of `EventSource`.
Nous pouvons interroger cette propriété pour connaître l'état de `EventSource`.

## Event types
## Types d'événements

By default `EventSource` object generates three events:
Par défaut, l'objet `EventSource` génère trois événements :

- `message` -- a message received, available as `event.data`.
- `open` -- the connection is open.
- `error` -- the connection could not be established, e.g. the server returned HTTP 500 status.
- `message` -- un message reçu, disponible en tant que `event.data`.
- `open` -- la connexion est ouverte.
- `error` -- la connexion n'a pas pu être établie, par exemple le serveur a renvoyé le statut HTTP 500.

The server may specify another type of event with `event: ...` at the event start.
Le serveur peut spécifier un autre type d'événement avec `event: ...` au début de l'événement.

For example:
Par exemple :

```
event: join
Expand All @@ -182,7 +182,7 @@ event: leave
data: Bob
```

To handle custom events, we must use `addEventListener`, not `onmessage`:
Pour gérer des événements personnalisés, nous devons utiliser `addEventListener`, pas `onmessage` :

```js
eventSource.addEventListener('join', event => {
Expand All @@ -198,74 +198,74 @@ eventSource.addEventListener('leave', event => {
});
```

## Full example
## Exemple complet

Here's the server that sends messages with `1`, `2`, `3`, then `bye` and breaks the connection.
Voici le serveur qui envoie des messages avec `1`, `2`, `3`, puis `bye` et rompt la connexion.

Then the browser automatically reconnects.
Ensuite, le navigateur se reconnecte automatiquement.

[codetabs src="eventsource"]

## Summary
## Résumé

`EventSource` object automatically establishes a persistent connection and allows the server to send messages over it.
L'objet `EventSource` établit automatiquement une connexion persistante et permet au serveur d'envoyer des messages par-dessus.

It offers:
- Automatic reconnect, with tunable `retry` timeout.
- Message ids to resume events, the last received identifier is sent in `Last-Event-ID` header upon reconnection.
- The current state is in the `readyState` property.
Cela offre :
- Reconnexion automatique, avec délai d'attente de `retry` réglable.
- Identifiants des messages pour reprendre les événements, le dernier identifiant reçu est envoyé dans l'en-tête `Last-Event-ID` lors de la reconnexion.
- L'état actuel est dans la propriété `readyState`.

That makes `EventSource` a viable alternative to `WebSocket`, as it's more low-level and lacks such built-in features (though they can be implemented).
Cela fait de `EventSource` une alternative viable à `WebSocket`, car il est plus bas niveau et manque de telles fonctionnalités intégrées (bien qu'elles puissent être implémentées).

In many real-life applications, the power of `EventSource` is just enough.
Dans de nombreuses applications réelles, la puissance de `EventSource` est juste suffisante.

Supported in all modern browsers (not IE).
Pris en charge dans tous les navigateurs modernes (pas IE).

The syntax is:
La syntaxe est :

```js
let source = new EventSource(url, [credentials]);
```

The second argument has only one possible option: `{ withCredentials: true }`, it allows sending cross-origin credentials.
Le deuxième argument n'a qu'une seule option possible: `{withCredentials: true}`, il permet d'envoyer des informations d'identification cross-origin.

Overall cross-origin security is same as for `fetch` and other network methods.
La sécurité globale de cross-origin est la même que pour `fetch` et d'autres méthodes réseau.

### Properties of an `EventSource` object
### Propriétés d'un objet `EventSource`

`readyState`
: The current connection state: either `EventSource.CONNECTING (=0)`, `EventSource.OPEN (=1)` or `EventSource.CLOSED (=2)`.
: L'état de connexion actuel : soit `EventSource.CONNECTING (=0)`, `EventSource.OPEN (=1)` ou `EventSource.CLOSED (=2)`.

`lastEventId`
: The last received `id`. Upon reconnection the browser sends it in the header `Last-Event-ID`.
: Le dernier `id` reçu. Lors de la reconnexion, le navigateur l'envoie dans l'en-tête `Last-Event-ID`.

### Methods
### Les méthodes

`close()`
: Closes the connection.
: Ferme la connexion.

### Events
### Les événements

`message`
: Message received, the data is in `event.data`.
: Message reçu, les données sont dans `event.data`.

`open`
: The connection is established.
: La connexion est établie.

`error`
: In case of an error, including both lost connection (will auto-reconnect) and fatal errors. We can check `readyState` to see if the reconnection is being attempted.
: En cas d'erreur, y compris la perte de connexion (se reconnectera automatiquement) et les erreurs fatales. Nous pouvons vérifier `readyState` pour voir si la reconnexion est tentée.

The server may set a custom event name in `event:`. Such events should be handled using `addEventListener`, not `on<event>`.
Le serveur peut définir un nom d'événement personnalisé dans `event:`. De tels événements doivent être gérés en utilisant `addEventListener`, pas `on<event>`.

### Server response format
### Format de réponse du serveur

The server sends messages, delimited by `\n\n`.
Le serveur envoie des messages, délimités par `\n\n`.

A message may have following fields:
Un message peut contenir les champs suivants :

- `data:` -- message body, a sequence of multiple `data` is interpreted as a single message, with `\n` between the parts.
- `id:` -- renews `lastEventId`, sent in `Last-Event-ID` on reconnect.
- `retry:` -- recommends a retry delay for reconnections in ms. There's no way to set it from JavaScript.
- `event:` -- event name, must precede `data:`.
- `data:` -- corps du message, une séquence de plusieurs `data` est interprétée comme un seul message, avec `\n` entre les parties.
- `id:` -- renouvelle `lastEventId`, envoyé dans `Last-Event-ID` lors de la reconnexion.
- `retry:` -- recommande un délai de relance pour les reconnexions en ms. Il n'y a aucun moyen de le définir à partir de JavaScript.
- `event:` -- nom de l'événement, doit précéder `data:`.

A message may include one or more fields in any order, but `id:` usually goes the last.
Un message peut inclure un ou plusieurs champs dans n'importe quel ordre, mais `id:` va généralement en dernier.