Как подключаться к нескольким WebSocket-серверам

Короткий ответ: подключение к множеству WebSocket-серверов нужно организовывать через единый менеджер соединений. Не создавайте new WebSocket(...) в случайных компонентах и функциях. Храните сокеты в Map, задавайте имя каждому серверу, проверяйте readyState, закрывайте соединения централизованно и отдельно продумайте переподключение

Схема:

ConnectionManager
  prices -> wss://prices.example.com/ws
  chat   -> wss://chat.example.com/ws
  events -> wss://events.example.com/ws

Минимальный менеджер соединений

class WebSocketManager {
  constructor() {
    this.connections = new Map();
  }

  connect(name, url) {
    if (this.connections.has(name)) {
      return this.connections.get(name);
    }

    const socket = new WebSocket(url);

    socket.addEventListener("open", () => {
      console.log(`${name}: connected`);
    });

    socket.addEventListener("close", () => {
      console.log(`${name}: closed`);
      this.connections.delete(name);
    });

    socket.addEventListener("error", () => {
      console.log(`${name}: error`);
    });

    this.connections.set(name, socket);
    return socket;
  }

  send(name, data) {
    const socket = this.connections.get(name);

    if (!socket || socket.readyState !== WebSocket.OPEN) {
      return false;
    }

    socket.send(JSON.stringify(data));
    return true;
  }

  close(name) {
    const socket = this.connections.get(name);
    socket?.close(1000, "Manual close");
    this.connections.delete(name);
  }

  closeAll() {
    for (const [name, socket] of this.connections) {
      socket.close(1000, `Close ${name}`);
    }

    this.connections.clear();
  }
}

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

const manager = new WebSocketManager();

manager.connect("prices", "wss://example.com/prices");
manager.connect("chat", "wss://example.com/chat");

manager.send("chat", {
  type: "message",
  text: "Привет",
});

Не все соединения нужно открывать сразу

Если пользователь не открыл чат, не нужно держать чат-сокет. Если график не виден на странице, не нужно подписываться на поток цен. Правильная организация часто означает не “открыть все серверы”, а “открывать нужное соединение в нужный момент”

Пример:

  • глобальные уведомления — после авторизации;
  • чат — при входе в раздел чата;
  • live-график — при открытии графика;
  • админские события — только для пользователя с правами.

Переподключение

Для каждого сервера задайте свою стратегию. Не делайте бесконечный агрессивный reconnect каждую миллисекунду

function reconnectWithDelay(connect, attempt) {
  const delay = Math.min(1000 * 2 ** attempt, 30000);
  setTimeout(connect, delay);
}

В реальном коде добавьте лимит попыток, jitter и проверку: нужно ли соединение еще пользователю

Еще один важный момент — не переподключайте сокет, который пользователь закрыл осознанно. Для этого храните флаг:

const connectionState = {
  chat: { shouldReconnect: true },
};

При logout или закрытии раздела ставьте shouldReconnect = false, а уже потом вызывайте close(). Иначе приложение само восстановит соединение, которое вы только что пытались закрыть

Авторизация

Если серверы требуют токен, не передавайте секреты в адрес без необходимости. Часто используют короткоживущий токен, cookie-сессию или первое сообщение после подключения:

socket.addEventListener("open", () => {
  socket.send(JSON.stringify({
    type: "auth",
    token: accessToken,
  }));
});

Выбор зависит от архитектуры. Главное — не открывать публичный WebSocket, через который можно получить личные данные

Частые ошибки

Первая ошибка — десятки соединений без учета лимитов браузера и сервера. Даже если WebSocket постоянный, он не бесплатный

Вторая ошибка — потерять ссылки на сокеты. Потом их невозможно корректно закрыть

Третья ошибка — отправлять данные до open. Используйте очередь сообщений или проверку readyState

Четвертая ошибка — один общий reconnect для всех серверов. Разные каналы могут иметь разные правила: чат можно переподключать мягче, критичные уведомления — активнее

Самопроверка

Создайте три подключения через менеджер, отправьте сообщение только в одно из них, затем вызовите closeAll(). В DevTools Network все открытые WS-соединения должны закрыться. Если какое-то соединение осталось, значит оно было создано в обход менеджера

Что почитать дальше по WebSocket

Если нужен общий маршрут по теме, откройте рубрику WebSocket. Для соседних задач пригодятся эти разборы:

Оцените статью
0 0 голоса
Рейтинг статьи
Подписаться
Уведомить о
guest

0 комментариев
Старые
Новые Популярные
Межтекстовые Отзывы
Посмотреть все комментарии
0
Оставьте комментарий! Напишите, что думаете по поводу статьи.x