Připomenutí existence „server-sent events” (SSE)

Kromně více známého a rozšířeného WebSocketu a klasického Ajaxového dotazování API serveru existuje také „server-sent events” (dále SSE). SSE slouží k jednosměrnému posílání informací ze serveru ke klientovi.


Obsah
  1. Hlavní vlastnosti
  2. Implementace na straně serveru
  3. Použití/naslouchání v JavaScriptu
  4. Možná (typická) použití
  5. Reference a související zdroje

Hlavní vlastnosti

Podrobněji rozebírá [sseVSws][mdn].

SSE pracuje přes protokol HTTP(S)1 (může být vstřícnější k firemním firewallům), je podporováno nativně2 v prohlížečích (z předchozího i na serverech) a relativně jednoduché na implementaci a pochopení (viz dále).

Nativní implementace navíc řeší znovupřipojováníspárovávání zpráv s identifikátory.

Klíčovými limitacemi je nepodpora binárních dat a protokol, v případě velmi komplexních/vytížených systémů.

Implementace na straně serveru

Zde použijeme MIME typ text/event-stream a zprávy posíláme v jednoduchém textovém UTF-8 formátu event stream.

Tedy se zápisem data: zpráva a oddělujeme je \n\n3. Ke zprávě lze dodat její jméno event: jméno a identifikátor id: 1. Tedy celkem:

data: Jen samotná zpráva

id: 1
event: pojmenovana_zprava
data: Druhá zpráva

Ukázka SSE dvou zpráv, které vytvořil server

Jako zprávu můžeme sapozřejmě použít JSON. Pro PHP bychom mohli tedy vytvořit funkci ve tvaru:

1
2
3
4
5
6
7
8
9
10
11
function eventEmmit($data= "", $event= false, $id= false){
    if($id)
        echo "id: $id\n";
    if($event)
        echo "event: $event\n";
    if(is_array($data))
        $data= json_encode($data);
    echo "data: $data\n\n";
    ob_end_flush();
    flush();
}

Ukázka jednoduché funkce pro zasílání SSE v PHP

1
2
3
4
5
6
7
8
9
10
11
12
13
define('EVENT_DELAY', 1);
header('Cache-Control: no-cache');
header('Content-Type: text/event-stream');
$id= 0;
function out($event, $data){
    global $id;
    eventEmmit($data, $event, id++);
    sleep(EVENT_DELAY);
}
while(true){
    $event= 'event_'.(rand(1, 10)>5 ? 'a': 'b');
    out($event, array( 'now'=> date(DATE_ISO8601) ));
}

Ukázka použití eventEmmit

Použití/naslouchání v JavaScriptu

Zde stačí inicializovat EventSource s cestou ke skriptu na serveru. Instance pak mimojiné obsahuje settery onmessage resp. onerror (k naslouchání nepojmenovaných zpráv resp. chyb), metodu addEventListener s jejíž pomocí se dají naslouchat jen vybrané zprávy (dle jména) a metodu close pro ukončení spojení.

1
2
3
4
5
6
7
8
9
10
11
const sse= new EventSource("cesta/ke/skriptu.php");
const parse= json_candidate=> { try{ return JSON.parse(json_candidate); } catch(e){ return json_candidate; } };
const log= ({ data= "" }= {})=> console.log(parse(data));

sse.addEventListener("event_a", log);
sse.addEventListener("event_b", log);
sse.onerror= console.error;
/*
    …
*/
sse.close();

Tedy ukázka pro dřívější serverovou část

Možná (typická) použití

  1. Tzv. „hot-reload”: Server a klient si pamatují poslední aktualizaci souboru/stránky. Pokud na serveru dojde ke změně, pomocí SSE pošle nové časové razítko klientovi a ten stránku přenačte (např. location.reload()).
  2. Rozšířením předchozího je donačítání příspěvků alá Twitter.
  3. Velmi podobné je také použití pro notifikace.

Reference a související zdroje

  1. [mdn] Using server-sent events – Přehledový článek dokumnetace k SSE
  2. [sseVSws] WebSockets vs. Server-Sent events/EventSource – Docela vyčerávající seznam o vlastnostech SSE a srovnání s WebSockets
  3. [rauschma] Poznámky o SSE – Axel Rauschmayer
  4. [postup-vývoje] Developing Real-Time Web Applications with Server-Sent Events
  5. [twitter-sse-demo] A demo of a very basic twitter clone that implements server sent events
  1. Nezabezpečená verze má limity na počet otevřených připojení, viz [mdn]

  2. Kromně starých prohlížečů, viz Can I use. Ale existuje např. polyfill (event-source-polyfill). 

  3. Víceřádkovou zprávu lze zapsat data: řádek 1.\ndata: řádek 2.