În acest articol, vom explora modul de utilizare a evenimentelor trimise de server pentru a permite clientului să primească actualizări automate de la server printr-o conexiune HTTP. De asemenea, vom analiza de ce este util acest lucru și vom arăta demonstrații practice despre cum să folosiți evenimentele trimise de server cu Node.js.
De ce sunt utile evenimentele trimise de server?
Web-ul se bazează pe mesajele HTTP de solicitare și răspuns. Browserul dvs. face o solicitare URL și serverul răspunde cu datele. Acest lucru poate duce la mai multe solicitări de browser și răspunsuri de server pentru imagini, CSS, JavaScript etc. Serverul nu poate face asta Iniţia mesaje către browser, deci cum poate indica faptul că datele s-au schimbat? Din fericire, puteți adăuga funcții precum știri live, rapoarte meteo și cotații bursiere cu evenimentele trimise de pe server.
Implementarea actualizărilor de date în direct folosind tehnologii web standard a fost întotdeauna posibilă:
- Web-ul în anii 1990 folosea reîmprospătarea full-page sau iframe.
- În anii 2000, Web-ul a introdus tehnologia Ajax, care poate folosi sondaje lungi pentru a solicita date și pentru a actualiza elementele DOM corespunzătoare cu informații noi.
Niciuna dintre opțiuni nu este ideală, deoarece browserul trebuie să declanșeze actualizarea. Dacă face solicitări prea des, nu se vor schimba date, așa că atât browserul, cât și serverul fac lucrări inutile. Dacă plasează comenzi prea încet, s-ar putea să rateze o actualizare importantă, iar prețul acțiunilor pe care le urmăriți s-ar putea prăbuși!
- Browserul face în continuare cererea inițială de a stabili o conexiune.
- Serverul returnează răspunsul la fluxul de evenimente și menține conexiunea deschisă.
- Serverul poate folosi această conexiune pentru a trimite mesaje text în orice moment.
- Datele primite declanșează un eveniment JavaScript în browser. Funcția de gestionare a evenimentelor poate analiza date și poate actualiza DOM.
În esență, SSE este un flux nesfârșit de date. Gândiți-vă la asta ca la descărcarea unui fișier infinit de mare în bucăți mici pe care le puteți intercepta și citi.
SSE a fost implementat pentru prima dată în 2006 și toate browserele majore acceptă acest standard. Este poate mai puțin cunoscut decât WebSockets, dar evenimentele trimise de server sunt mai simple, folosesc HTTP standard, acceptă comunicarea unidirecțională și oferă reconectare automată. Acest tutorial oferă exemplu de cod Node.js fără module terță parte, dar SSE este disponibil în alte limbi de pe partea serverului Inclusiv PHP.
Pornire rapidă a evenimentelor trimise de pe server
Următoarea demonstrație implementează un server web Node.js care scoate un număr aleator între 1 și 1000 la un interval aleator cel puțin o dată la trei secunde.
Mai jos este demonstrația noastră Node.js SSE (puteți Deschideți-l într-o filă separată de browser Daca preferi).
Codul folosește Node.js standard http
Și url
Module pentru crearea unui server web și analizarea adreselor URL:
import http from "node:http";
import url from "node:url";
Serverul examinează solicitarea URL primită și reacționează când întâlnește un fișier /random
drum:
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`);
Răspunde inițial cu antetul fluxului de evenimente HTTP SSE:
function sseStart(res) {
res.writeHead(200, {
Content-Type: "text/event-stream",
Cache-Control: "no-cache",
Connection: "keep-alive"
});
}
O altă funcție trimite un număr aleator și se autoapelează după ce a trecut o perioadă aleatoare:
function sseRandom(res) {
res.write("data: " + (Math.floor(Math.random() * 1000) + 1) + "\n\n");
setTimeout(() => sseRandom(res), Math.random() * 3000);
}
Dacă rulați codul local, puteți testa răspunsul folosind rostogolire În terminalul dvs.:
$> curl -H Accept:text/event-stream http://localhost:8000/random
data: 481
data: 127
data: 975
El apasă Control | cataplasmă Și C Pentru a finaliza cererea.
Apelurile JavaScript din partea clientului browserului /random
URI folosind Constructor al obiectului EventSource:
const source = new EventSource("/random");
Datele primite conduc la a message
Managerul de evenimente unde următorul șir data:
Disponibil în obiect eveniment .data
Proprietate:
source.addEventListener('message', e => {
console.log('RECEIVED', e.data);
});
Notite importante
- Îi place Aduce()browserul dvs. face o solicitare HTTP standard, așa că poate fi necesar să lucrați cu aceasta CSP, curs Și opțional treci din nou
{ withCredentials: true }
argument pentruEventSource
Generator pentru trimiterea cookie-urilor. - Serverul trebuie să păstreze individul
res
Obiecte de răspuns pentru fiecare utilizator conectat pentru a le trimite date. Se realizează în codul de mai sus prin trecerea valorii din închidere la apelul următor. - Datele mesajului pot fi doar un șir (eventual JSON) trimis în format
data: <message>\n\n
. Retururile de transfer încheiate sunt esențiale. -
res.end()
dar… - Când are loc o întrerupere, browserul încearcă automat să se reconnecteze; Nu este nevoie să introduceți propriul cod de reapelare.
Evenimente avansate trimise de pe server
SSE nu necesită mai mult cod decât cel descris mai sus, dar secțiunile următoare discută mai multe opțiuni.
Un canal față de multe canale SSE
Serverul poate furniza orice număr de adrese URL de canal SSE. De exemplu:
/latest/news
/latest/weather
/latest/stockprice
Acest lucru poate fi practic dacă o singură pagină afișează un singur subiect, dar mai puțin dacă o singură pagină afișează știri, vreme și cotații bursiere. În acest caz, serverul trebuie să mențină trei conexiuni per utilizator, ceea ce poate duce la probleme de memorie pe măsură ce traficul crește.
O opțiune alternativă este de a furniza o singură adresă URL pentru punctul final, de ex /latest
Care trimite orice tip de date pe un singur canal de comunicare. Browserul poate indica subiecte de interes în șirul de interogare URL – de ex. /latest?type=news,weather,stockprice
– Pentru ca serverul să poată restricționa răspunsurile SSE la anumite mesaje.
Trimiterea de date diferite pe un canal
Mesajele de pe server pot avea un link event:
Trecut pe linia de mai sus data:
Identificați tipuri specifice de informații:
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 }
Asta va Nu Mutați partea clientului "message"
Organizatorul evenimentului. Trebuie să adăugați handlere pentru fiecare tip event
. De exemplu:
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 }%)`;
});
Opțional, serverul poate trimite și un mesaj id:
după A data:
Linia:
event: news
data: SSE is great!
id: 42
Dacă conexiunea este întreruptă, browserul îl trimite pe ultimul id
Reveniți la server la Last-Event-ID
Antet HTTP, astfel încât serverul să poată retrimite orice mesaj fără răspuns.
Cel mai recent ID client este disponibil și în obiectul eveniment .lastEventId
Proprietate:
source.addEventListener('news', e => {
console.log(`last ID: ${ e.lastEventId }`);
document.getElementById('headline')
.textContent = e.data;
});
Deși reconectarea este automată, serverul dvs. poate ști că nu sunt așteptate date noi pentru o perioadă specificată, deci nu este nevoie să mențineți un canal de conexiune activ. Serverul poate trimite un retry:
Un răspuns în milisecunde fie singur, fie ca parte a mesajului final. De exemplu:
retry: 60000
data: Please don't reconnect for another minute!
La primire, browserul va renunța la conexiunea SSE și va încerca să se reconecteze după ce perioada de întârziere a trecut.
Alți handler de evenimente
Lângă "message"
Și evenimentele numite, le puteți crea și pe acestea "open"
Și "error"
Handler-uri în JavaScript pe partea clientului.
acea "open"
Evenimentul este declanșat atunci când se stabilește o conexiune la server. Poate fi folosit pentru a rula cod de configurare suplimentar sau pentru a inițializa elemente DOM:
const source = new EventSource('/sse1');
source.addEventListener('open', e => {
console.log('SSE connection established.');
});
acea "error"
Evenimentul este declanșat atunci când conexiunea la server eșuează sau se încheie. Puteți inspecta obiectul evenimentului .eventPhase
Funcție pentru a verifica ce s-a întâmplat:
source.addEventListener('error', e => {
if (e.eventPhase === EventSource.CLOSED) {
console.log('SSE connection closed');
}
else {
console.log('error', e);
}
});
Amintiți-vă că nu este nevoie să vă reconectați: Se întâmplă automat.
Terminați conexiunile SSE
Browserul poate termina conexiunea SSE folosind obiectul EventSource .close()
drum. De exemplu:
const source = new EventSource('/sse1');
setTimeout(() => source.close(), 3_600_000);
Serverul poate opri conexiunea prin:
- filmare
res.end()
Sau trimite unretry:
întârziere - Returnează starea HTTP 204 când același browser încearcă să se reconecteze.
Browserul poate restabili conexiunea doar prin crearea unei noi conexiuni EventSource
Poartă.
Concluzie
Evenimentele din partea serverului oferă o modalitate de implementare a actualizărilor paginilor live, care este probabil mai ușoară, mai practică și mai ușoară decât Fetch()
Sondaj bazat pe Ajax. Complexitate la capătul serverului. va trebui să:
- Păstrați toate conexiunile de utilizator active în memorie și
- Declanșează transferurile de date când ceva se schimbă.
Dar acest lucru este în întregime în controlul tău, iar scalarea nu ar trebui să fie mai complicată decât orice altă aplicație web.
Singurul dezavantaj este că SSE nu vă permite să trimiteți mesaje din browser către server (în afară de cererea inițială de conectare). Puteți folosi Ajax, dar acest lucru este prea lent pentru aplicații precum jocurile de acțiune. Pentru o comunicare corectă în două sensuri, aveți nevoie de WebSockets. Vom avea un nou tutorial despre asta în curând!
„Student. Organizator subtil fermecător. Susținător al muzicii certificat. Scriitor. Făcător de-a lungul vieții. Iubitor de Twitter.”
More Stories
Nintendo nu poate repara Noul tău 3DS deoarece are piese fără piese
Yamaha MT-09 SP este bicicleta perfectă pentru cicliștii solitar
Google Pixel 9 bate peste greutatea sa – channelnews