Библиотеки
SSE-клиент

SseService

Сервис SseService предназначен для управления серверными событиями (Server-Sent Events, SSE) в приложении Angular. Он устанавливает соединение с сервером, получает события и обрабатывает их.

Основные возможности

  • Автоматическое управление авторизацией: сервис автоматически добавляет токен в заголовки запроса и обновляет его при получении 401 ошибки.
  • Автоматические переподключения: при сетевых ошибках или обрывах соединения происходит автоматическое переподключение.
  • Обработка ошибок: различные типы ошибок обрабатываются по-разному (фатальные ошибки завершают соединение, временные - инициируют повтор).
  • RxJS-интеграция: использование Observable для удобной работы с потоком событий.

Типы данных

SseConfig

Конфигурация для подключения к SSE:

interface SseConfig {
  /** URL для подключения */
  url: string;
  /** HTTP-метод (по умолчанию GET) */
  method?: string;
  /** HTTP-заголовки */
  headers?: Record<string, string>;
  /** Тело запроса */
  body?: string;
}

SseMessage

Структура SSE-сообщения:

interface SseMessage {
  /** Уникальный идентификатор сообщения */
  id: string;
  /** Тип события (по умолчанию 'message') */
  event: string;
  /** Данные сообщения */
  data: string;
}

Методы

open

open(config: SseConfig): Observable<SseMessage>

Открывает SSE-соединение и возвращает Observable поток сообщений.

Параметры:

ПараметрТипОбязателенОписаниеЗначение по умолчанию
urlstringДаURL-адрес для подключения к SSE сервису-
methodstringНетHTTP-метод запроса'GET'
headersRecord<string, string>НетДополнительные HTTP-заголовки. Токен авторизации добавляется автоматически
bodystringНетТело запросаundefined

Возвращает: Observable<SseMessage> - поток SSE-сообщений.

Обработка авторизации:

  • Токен авторизации добавляется автоматически.
  • При получении 401 ошибки сервис автоматически обновляет токен и переподключается.
  • Если обновление токена не удалось, соединение завершается с ошибкой.

Обработка ошибок:

  • Фатальные ошибки (ошибки клиента 4xx кроме 401 и 429, неверный Content-Type): завершают соединение без повтора.
  • Временные ошибки (сетевые ошибки, ошибки сервера 5xx, 429): инициируют автоматическое переподключение.
  • Серверные события FatalError: если сервер отправляет событие с типом FatalError, соединение завершается.

Управление соединением

Для управления соединением используйте стандартные механизмы RxJS:

  • Открытие соединения: подпишитесь на Observable, возвращаемый методом open().
  • Закрытие соединения: отпишитесь от Observable используя unsubscribe(), take(), takeUntil(), takeUntilDestroyed() и другие операторы RxJS.

Примеры использования

Базовый пример

import { Component, OnInit, OnDestroy } from '@angular/core';
import { SseService, SseMessage } from '@diasoft/qpalette-sse-client';
import { Subscription } from 'rxjs';
 
@Component({
  selector: 'app-example',
  template: `<p>{{ message }}</p>`,
})
export class ExampleComponent implements OnInit, OnDestroy {
  message: string = '';
  private subscription?: Subscription;
 
  constructor(private sseService: SseService) {}
 
  ngOnInit(): void {
    this.subscription = this.sseService
      .open({ url: 'http://localhost:4300/events' })
      .subscribe({
        next: (event: SseMessage) => {
          console.log('Получено событие:', event.event);
          this.message = event.data;
        },
        error: (err) => {
          console.error('Ошибка SSE-соединения:', err);
        },
        complete: () => {
          console.log('SSE-соединение закрыто');
        }
      });
  }
 
  ngOnDestroy(): void {
    this.subscription?.unsubscribe();
  }
}

Использование с takeUntilDestroyed

import { Component, OnInit } from '@angular/core';
import { takeUntilDestroyed } from '@angular/core/rxjs-interop';
import { SseService, SseMessage } from '@diasoft/qpalette-sse-client';
 
@Component({
  selector: 'app-example',
  template: `<p>{{ message }}</p>`,
})
export class ExampleComponent implements OnInit {
  message: string = '';
 
  constructor(private sseService: SseService) {}
 
  ngOnInit(): void {
    this.sseService
      .open({ url: 'http://localhost:4300/events' })
      .pipe(takeUntilDestroyed())
      .subscribe({
        next: (event: SseMessage) => {
          this.message = event.data;
        },
        error: (err) => {
          console.error('Ошибка SSE:', err);
        }
      });
  }
}

POST-запрос с телом

import { Component, OnInit } from '@angular/core';
import { SseService, SseMessage } from '@diasoft/qpalette-sse-client';
 
@Component({
  selector: 'app-example',
  template: `<p>{{ message }}</p>`,
})
export class ExampleComponent implements OnInit {
  message: string = '';
 
  constructor(private sseService: SseService) {}
 
  ngOnInit(): void {
    this.sseService
      .open({
        url: 'http://localhost:4300/events',
        method: 'POST',
        headers: {
          'Content-Type': 'application/json'
        },
        body: JSON.stringify({ filter: 'important' })
      })
      .subscribe({
        next: (event: SseMessage) => {
          this.message = event.data;
        }
      });
  }
}

Обработка разных типов событий

import { Component, OnInit } from '@angular/core';
import { SseService, SseMessage } from '@diasoft/qpalette-sse-client';
 
@Component({
  selector: 'app-example',
  template: `
    <div>
      <p>Статус: {{ status }}</p>
      <p>Данные: {{ data }}</p>
    </div>
  `,
})
export class ExampleComponent implements OnInit {
  status: string = '';
  data: string = '';
 
  constructor(private sseService: SseService) {}
 
  ngOnInit(): void {
    this.sseService
      .open({ url: 'http://localhost:4300/events' })
      .subscribe({
        next: (event: SseMessage) => {
          switch (event.event) {
            case 'status':
              this.status = event.data;
              break;
            case 'data':
              this.data = event.data;
              break;
            case 'message':
            default:
              console.log('Сообщение:', event.data);
          }
        }
      });
  }
}

Примечания

  • Убедитесь, что сервер возвращает правильный Content-Type: text/event-stream заголовок.
  • Токен авторизации добавляется автоматически, не нужно передавать его вручную в headers.
  • При отписке от Observable соединение закрывается автоматически.
  • Для обработки JSON-данных используйте JSON.parse(event.data) в обработчике сообщений.