Server-Sent Events — bir tomonlama real-time

~15 daq · NestJS · Ilg'or mavzular

Muammodan boshlaylik

Foydalanuvchi katta faylni yukladi. Server qayta ishlamoqda. Foydalanuvchi progressni ko'rmoqchi:

Qayta ishlanmoqda... 20%
Qayta ishlanmoqda... 55%
Qayta ishlanmoqda... 90%
Tayyor! ✅

WebSocket ishlatishingiz mumkin — lekin u ikki tomonlama. Bu yerda faqat server → client yo'nalish kerak, client hech narsa yubormaydi. WebSocket bu holda ortiqcha murakkab.

SSE aynan shu uchun.


SSE nima?

SSE (Server-Sent Events) — serverdan clientga bir tomonlama uzluksiz ma'lumot oqimi.

WebSocket:  client ◄──────────► server  (ikki tomonlama)
SSE:        client ◄─────────── server  (faqat server → client)

Hayotiy o'xshatma

Radio stantsiya. Stantsiya uzatadi — siz eshitasiz. Siz stantsiyaga gapirolmaysiz. Aynan bir tomonlama kerak bo'lganda — SSE WebSocket dan sodda va qulay.

Qachon ishlatiladi:

  • Fayl yuklash progressi
  • Yangiliklar lenti
  • Narx yangilanishlari
  • Bildirish xabarlari

NestJS da SSE

@Sse() dekoratori Observable qaytaradi. Observable — vaqt o'tishi bilan bir necha qiymat beradigan ob'ekt. Har yangi qiymat clientga yuboriladi.


Fayl tuzilmasi

src/
  progress/
    progress.controller.ts
    progress.module.ts

Kod

// progress/progress.controller.ts
import { Controller, Sse } from '@nestjs/common';
import { Observable } from 'rxjs';

@Controller('progress')
export class ProgressController {

  @Sse('stream')
  stream(): Observable<{ data: any }> {
    let percent = 0;

    return new Observable((subscriber) => {
      const timer = setInterval(() => {
        percent += 20;
        subscriber.next({ data: { percent } }); // ← clientga yuborish

        if (percent >= 100) {
          subscriber.complete(); // ← oqim tugadi
          clearInterval(timer);
        }
      }, 1000);

      // Client uzilsa — timerni tozalash
      return () => clearInterval(timer);
    });
  }
}

GET /progress/stream ga ulanganingizda — har soniyada { percent: 20 }, { percent: 40 } ... keladi.


Nima uchun { data: ... } format?

SSE protokoli shunday ishlaydi — har xabar data: prefiksi bilan yuboriladi. NestJS avtomatik qiladi, lekin ob'ektni { data: ... } ga o'rash shart.

// To'g'ri:
subscriber.next({ data: { percent: 20 } })

// Noto'g'ri:
subscriber.next({ percent: 20 }) // ← SSE standarti buziladi

Frontend dan qabul qilish

const eventSource = new EventSource('/progress/stream');

eventSource.onmessage = (event) => {
  const data = JSON.parse(event.data);
  console.log(`Progress: ${data.percent}%`);

  if (data.percent >= 100) {
    eventSource.close(); // ← tugadi, ulanishni yopamiz
  }
};

EventSource — brauzerni o'zida bor, hech qanday kutubxona kerak emas.


SSE vs WebSocket

SSE WebSocket
Yo'nalish Server → client Ikki tomonlama
Murakkablik Sodda Murakkabrok
Reconnect Avtomatik Qo'lda
Qachon Progress, feed Chat, o'yin

Tez-tez uchraydigan xatolar

1. EventSource ishlamayapti

EventSource's response has a MIME type ("application/json") that is not "text/event-stream"

Sababi: @Sse() o'rniga @Get() ishlatilgan. Yechim: @Sse('stream') dekoratorini tekshiring.


2. Client uzilganda timer to'xtamayapti Sababi: Observable dan return () => clearInterval(timer) unutilgan. Yechim: Cleanup funksiyasini qaytaring — server resursi sarf qilmaydi.


Xulosa

  • SSE — serverdan clientga bir tomonlama oqim
  • @Sse() dekoratori — NestJS da ishlatish
  • Observable — vaqt o'tishi bilan qiymat yubora oladi
  • { data: ... } formatida yuborish shart
  • Frontend da EventSource — kutubxona shart emas
  • Progress, live feed, bildirishnomalar uchun ideal

Keyingi dars: 39-dars: Microservices — asoslar, RabbitMQ