Czytanie zdarzeń SSE
Polecenie: dane przychodzą jako fragmenty bajtów. Odczytaj zdarzenia rozdzielone pustą linią. Nie zakładaj, że jeden fragment sieciowy to jedna wiadomość. Uwzględnij polskie znaki, emoji i różne zakończenia linii.
Sprawdza: rozumienie transmisji i parsowania.
Kontrakt: parseSSE(bytes, maxBufferChars = 64000) to async generator, który dla AsyncIterable<Uint8Array> zwraca zdarzenia {event, data, id?}. To podzbiór SSE: pola data/event/id, komentarze, LF/CRLF/CR, bez ponownego połączenia i pola retry. Końcowe zdarzenie bez separatora jest odrzucane. Za duża linia lub zdarzenie rzuca błąd z komunikatem zawierającym too large.
Dopytanie: jak wznowić od ostatniego ID? To zadanie późniejsze; najpierw poznaj SSE i streaming.
Przećwiczysz
- Dekodować UTF-8 między fragmentami
- Buforować niedomknięte linie i zdarzenia
- Obsłużyć LF, CRLF i samo CR
- Ograniczyć pamięć
Testy (3)
Testy przeniesione z reference.test.ts materiału źródłowego (node:test). W przeglądarce działają z tym samym zestawem asercji.
SSE: każdy bajt osobno, UTF-8, CRLF, komentarze i wiele data
const got = await collect(parseSSE(chunks(': hi\r\nid: 7\r\nevent: token\r\ndata: żółć 😀\r\ndata: linia2\r\n\r\ndata: koniec\n\n', 1)));
assert.deepEqual(got, [{ id: '7', event: 'token', data: 'żółć 😀\nlinia2' }, { id: '7', event: 'message', data: 'koniec' }]);SSE: niedomknięty event i limit pamięci
assert.deepEqual(await collect(parseSSE(chunks('data: brak separatora', 4))), []);
await assert.rejects(collect(parseSSE(chunks('data: 123456\n\n', 1), 4)), /too large/);SSE: sam CR, reset id oraz pusta data
assert.deepEqual(await collect(parseSSE(chunks('id: 1\rdata: a\r\rid:\rdata:\r\r', 1))), [
{ id: '1', event: 'message', data: 'a' }, { id: '', event: 'message', data: '' }]);Powiązane pytania
Dokumentacja
Źródło: AI & Agents — ćwiczenia praktyczne — Autorskie ćwiczenie z programu nauki, nie potwierdzone zadanie rekrutacyjne.