Skip to content

Commit f394522

Browse files
Revert "Delete article.md"
This reverts commit d397c21.
1 parent 88b7665 commit f394522

File tree

1 file changed

+266
-0
lines changed

1 file changed

+266
-0
lines changed
Lines changed: 266 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,266 @@
1+
# Server Sent Events
2+
3+
La specifica [Server-Sent Events](https://html.spec.whatwg.org/multipage/comms.html#the-eventsource-interface) descrive una classe built-in `EventSource`, che mantiene la connessione con il server e permette di ricevere eventi da esso.
4+
5+
In modo simile ai `WebSocket`, la connessione è persistente.
6+
7+
Ci sono però delle differenze sostanziali:
8+
9+
| `WebSocket` | `EventSource` |
10+
|-------------|---------------|
11+
| Bidirezionale: sia il client che il server possono scambiare messaggi | Unidirezionale: solamente il server può inviare messaggi |
12+
| Dati binari e testuali | Solo testuali |
13+
| Protocollo WebSocket | HTTP standard |
14+
15+
`EventSource` è un modo meno potente di comunicare con il server rispetto ai `WebSocket`.
16+
17+
Perché dovremmo usarli?
18+
19+
La ragione principale: è semplice da usare. In molte applicazioni, la potenza dei `WebSocket` è anche troppa.
20+
21+
Se abbiamo necessità di ricevere un flusso di dati da un server: che siano messaggi di chat o variazioni di prezzo dei mercati. Allora è ciò per cui `EventSource` è fatto. Supporta anche l'auto riconnessione, la qualcosa dovremmo invece implementare manualmente nei `WebSocket`. Oltretutto, è un normalissimo HTTP, e non un nuovo protocollo.
22+
23+
## Ottenere i messaggi
24+
25+
Per cominciare a ricevere messaggi, dobbiamo solamente creare un `new EventSource(url)`.
26+
27+
Il browser si connetterà all'url e terrà la connessione aperta, in attesa di eventi.
28+
29+
Il server dovrebbe rispondere con status 200 ed header `Content-Type: text/event-stream`, dopodiché mantenere aperta la connessione e scrivere i messaggi all'interno di esso in un formato speciale del tipo:
30+
31+
```
32+
data: Message 1
33+
34+
data: Message 2
35+
36+
data: Message 3
37+
data: of two lines
38+
```
39+
40+
- Un messaggio di testo segue la stringa `data:`, lo spazio dopo la virgola è opzionale.
41+
- I messaggi sono delimitati con un doppio line break `\n\n`.
42+
- Per inviare un line break `\n`, possiamo inviare immediatamente un altro `data:` (il terzo messaggio nell'esempio precedente).
43+
44+
In pratica, i messaggi complessi sono solitamente inviati tramite oggetti codificati in JSO. I Line-breaks sono codificati come `\n`, e in questo modo i messaggi `data:` multiriga non sono necessari
45+
46+
Ad esempio:
47+
48+
```js
49+
data: {"user":"John","message":"First line*!*\n*/!* Second line"}
50+
```
51+
52+
...In questo modo possiamo assumere che ogni `data` contenga esattamente un messaggio.
53+
54+
Per ognuno di questi messaggi, viene generato l'evento `message`:
55+
56+
```js
57+
let eventSource = new EventSource("/events/subscribe");
58+
59+
eventSource.onmessage = function(event) {
60+
console.log("New message", event.data);
61+
//logghera' 3 volte per il data stream poco sopra
62+
};
63+
64+
// oppure eventSource.addEventListener('message', ...)
65+
```
66+
67+
### Richieste Cross-origin
68+
69+
`EventSource` supporta le richieste cross-origin, come `fetch` e qualunque altro metodo di rete. Possiamo usare qualunque URL:
70+
71+
```js
72+
let source = new EventSource("https://another-site.com/events");
73+
```
74+
Il server remoto otterrà l'header `Origin` e dovrà rispondere con `Access-Control-Allow-Origin` per continuare.
75+
76+
Per inviare credenziali, dovremmo impostare le opzioni aggiuntive `withCredentials`, in questo modo:
77+
78+
```js
79+
let source = new EventSource("https://another-site.com/events", {
80+
withCredentials: true
81+
});
82+
```
83+
84+
Si prega di guardare il capitolo <info:fetch-crossorigin> per maggiori informazioni sugli headers cross-origin.
85+
86+
87+
## Riconnessione
88+
89+
In fase di creazione, `new EventSource` si connette al server, e se la connessione si interrompe -- si riconnette.
90+
91+
Ciò è molto conveniente, dal momento che non ci dobbiamo curare della cosa.
92+
93+
C'è un piccolo ritardo tra le riconnessioni, pochi secondi di default.
94+
95+
Il server può impostare il ritardo raccomandato usando `retry:` nella risposta (in millisecondi)
96+
97+
```js
98+
retry: 15000
99+
data: Hello, I set the reconnection delay to 15 seconds
100+
```
101+
102+
Il `retry:` può arrivare insieme ad altri dati, o come messaggio singolo.
103+
104+
Il browser dovrebbe attendere questi millisecondi prima di riconnettersi. O anche di più, ad esempio se il browser sa (dall'OS) che non c'è connessione in quel momento, può attendere fino a quando la connessione non ritorna, e successivamente riprovare.
105+
106+
- Se il server vuole che il browser smetta di riconnettersi, dovrebbe rispondere con uno status HTTP 204.
107+
- Se il browser vuole chiudere la connessione, dovrebbe chiamare il metodo `eventSource.close()`:
108+
109+
```js
110+
let eventSource = new EventSource(...);
111+
112+
eventSource.close();
113+
```
114+
Inoltre, non avverrà alcuna riconnessione se la risposta ha un `Content-type` non valido o se il suo HTTP status è diverso da 301, 307, 200 o 204. In questi casi verrà emesso l'evento `"error"`, e il browser non si riconnetterà.
115+
116+
```smart
117+
Quando una connessione è finalemente chiusa, non ci sarà modo di "riaprirla". Se volessimo riconnetterci nuovamente, dovremmo ricreare un nuovo `EventSource`.
118+
```
119+
120+
## Message id
121+
122+
Quando una connessione si interrompe per motivi di problemi di rete, ogni lato non può essere sicuro di quale messaggi siano stati ricevuti, e quali no.
123+
Per riprendere correttamente la connessione, ogni messaggio dovrebbe avere un campo `id`, come questo:
124+
```
125+
data: Message 1
126+
id: 1
127+
128+
data: Message 2
129+
id: 2
130+
131+
data: Message 3
132+
data: of two lines
133+
id: 3
134+
```
135+
Quando viene ricevuto un messaggio con `id:`, il browser:
136+
137+
- Imposta la proprietà `eventSource.lastEventId` su quel valore.
138+
- In fase di riconnessione invia l'header `Last-Event-ID` con quell'`id`, in modo da permettere al server di reinviare i messaggi successivi.
139+
140+
```smart header="Inserisci `id:` dopo `data:`"
141+
Nota bene: l'`id` viene aggiunto dopo il messaggio `data` dal server, per assicurarsi che `lastEventId` venga aggiornato solamente dopo che il messaggio sia stato ricevuto.
142+
```
143+
144+
## Stato della conessione: readyState
145+
146+
L'oggetto `EventSource` possiede la proprietà `readyState`, che può assumere uno dei seguenti valori:
147+
148+
```js no-beautify
149+
EventSource.CONNECTING = 0; // connessione o riconnessione
150+
EventSource.OPEN = 1; // connesso
151+
EventSource.CLOSED = 2; // connessione chiusa
152+
```
153+
154+
Quando viene creato un oggetto, o se la connessione è assente, viene valorizzato sempre a `EventSource.CONNECTING` (equivale a `0`).
155+
156+
Possiamo interrogare questa proprietà per sapere lo stato di `EventSource`.
157+
158+
## Tipi di evento
159+
160+
Di base l'oggetto `EventSource` genera tre eventi:
161+
162+
- `message` -- un messaggio ricevuto, disponibile come `event.data`.
163+
- `open` -- la connessione è aperta.
164+
- `error` -- la connessaione non può essere stabilita, ad esempio, il server ha risposto con lo status HTTP 500.
165+
166+
Il server può specificare un altro tipo di evento con `event: ...` all'inizio dell'evento.
167+
168+
Per esempio:
169+
170+
```
171+
event: join
172+
data: Bob
173+
174+
data: Hello
175+
176+
event: leave
177+
data: Bob
178+
```
179+
180+
Per gestire eventi custom, dobbiamo usare `addEventListener`, e non `onmessage`:
181+
182+
```js
183+
eventSource.addEventListener('join', event => {
184+
alert(`Joined ${event.data}`);
185+
});
186+
187+
eventSource.addEventListener('message', event => {
188+
alert(`Said: ${event.data}`);
189+
});
190+
191+
eventSource.addEventListener('leave', event => {
192+
alert(`Left ${event.data}`);
193+
});
194+
```
195+
196+
## Esempio completo
197+
198+
Qui c'è il server che invia messaggi con `1`, `2`, `3`, ed infine `bye` interrompendo la connessione.
199+
200+
Dopo il browser si riconnette automaticamente.
201+
202+
[codetabs src="eventsource"]
203+
204+
## Riepilogo
205+
206+
L'oggetto `EventSource` stabilisce automaticamente una connessione persistente e permette al server di inviare dei messaggi attraverso di essa.
207+
208+
Offrendo:
209+
- Riconnessione automatica, con timeout di `retry` regolabili.
210+
- Id dei messaggi per riprendere gli eventi, l'ultimo id ricevuto viene inviato nell'header `Last-Event-ID` in fase di riconnessione.
211+
- Lo stato corrente è dentro la proprietà `readyState`.
212+
213+
Ciò rende `EventSource` una valida alternativa ai `WebSocket`, il quale è più a basso livello e manca di alcune funzionalità built-in (sebbene possano essere implementate).
214+
215+
In molte applicazioni reali, la potenza di `EventSource` è già sufficiente.
216+
217+
Supportato in tutti i browser moderni (non IE).
218+
219+
La sintassi è:
220+
221+
```js
222+
let source = new EventSource(url, [credentials]);
223+
```
224+
225+
Il secondo argomento consta di una sola opzione possibile: `{ withCredentials: true }`, la quale permette di inviare credenziali cross-origin.
226+
227+
Complessivamente la sicurezza del cross-origin è la stessa di `fetch` e altri metodi di rete.
228+
229+
### Proprietà di un oggetto `EventSource`
230+
231+
`readyState`
232+
: Lo stato corrente della connessione: uno tra `EventSource.CONNECTING (=0)`, `EventSource.OPEN (=1)` o `EventSource.CLOSED (=2)`.
233+
234+
`lastEventId`
235+
: L'ultimo `id` ricevuto.In fase di riconnessione il browser lo invia nell'header `Last-Event-ID`.
236+
237+
### Metodi
238+
239+
`close()`
240+
: Chiude la connessione.
241+
242+
### Eventi
243+
244+
`message`
245+
: Messagio ricevuto, il dato è dentro `event.data`.
246+
247+
`open`
248+
: La connessione è stabilita.
249+
250+
`error`
251+
: In caso di errori, inclusi la connessione persa (con riconnessione automatica) ed errori fatali. Possiamo controllare `readyState` per vedere se è stata tentata la riconnessione.
252+
253+
Il server può impostare un evento personalizzato dentro `event:`. Questi eventi andrebbero gestiti usando `addEventListener`, e non `on<event>`.
254+
255+
### Formato della risposta del server
256+
257+
Il server invia messaggi, delimitati da `\n\n`.
258+
259+
Un messaggio può avere i seguenti campi:
260+
261+
- `data:` -- corpo del messaggio, una sequenza di `data` multipli viene interpretata come un messaggio singolo, con `\n` tra la parti.
262+
- `id:` -- aggiorna `lastEventId`, inviato dentro `Last-Event-ID` in fase di riconnessione.
263+
- `retry:` -- raccomanda una ritardo nel tentativo di riconessione in millisecondi. Non c'è modo di impostarlo da JavaScript.
264+
- `event:` -- event name, must precede `data:`.
265+
266+
Un messaggio può includere uno o più campi in qualunque ordine, ma l'`id:` solitamente va per ultimo.

0 commit comments

Comments
 (0)