Что такое WebSockets и как реализовать live-обновления на фронте и бэке

10 минут чтения
Средний рейтинг статьи — 4.9

Современные веб-приложения требуют не только отображения статических данных, но и мгновенной реакции на изменения — будь то новые сообщения в чате, обновления курсов валют, уведомления или онлайн-игры. Классический HTTP-запрос «клиент → сервер» плохо подходит для подобных задач, ведь данные передаются только по инициативе клиента.

Здесь на помощь приходят WebSockets — технология, позволяющая устанавливать постоянное двунаправленное соединение между клиентом и сервером.

Как работают WebSockets

  • При первом подключении клиент отправляет HTTP-запрос с заголовком Upgrade, предлагая серверу перейти на протокол WebSocket.
  • Если сервер поддерживает WebSockets, соединение «апгрейдится» и открывается двунаправленный канал.
  • Теперь клиент и сервер могут обмениваться сообщениями в реальном времени, без дополнительных запросов.

В отличие от polling (регулярного опроса сервера) или long-polling (длинных висящих запросов), WebSocket-соединение:

  • экономит трафик (нет постоянных HTTP-заголовков),
  • снижает задержку доставки,
  • может работать в обе стороны: и сервер, и клиент могут первыми инициировать отправку.
// Установка соединения
const socket = new WebSocket("ws://localhost:3000");
 
// Событие открытия соединения
socket.addEventListener("open", () => {
  console.log("Соединение установлено");
  socket.send("Привет, сервер!");
});
 
// Получение сообщений от сервера
socket.addEventListener("message", (event) => {
  console.log("Сообщение от сервера:", event.data);
});
 
// Обработка закрытия
socket.addEventListener("close", () => {
  console.log("Соединение закрыто");
});

Использование на бэкенде (пример на Node.js с ws)

Установим библиотеку:

npm install ws

Простейший сервер:

import { WebSocketServer } from "ws";
 
const wss = new WebSocketServer({ port: 3000 });
 
wss.on("connection", (ws) => {
  console.log("Новый клиент подключен");
 
  ws.on("message", (message) => {
    console.log("Получено:", message.toString());
    ws.send(`Эхо: ${message}`);
  });
 
  ws.on("close", () => {
    console.log("Клиент отключился");
  });
});

Теперь клиенты могут подключаться и обмениваться сообщениями в реальном времени.

Безопасность при работе с WebSockets

Так как WebSocket-соединение остаётся открытым длительное время, важно заранее подумать о безопасности. Вот три основных практики:

Аутентификация соединений

Используйте JWT-токены или другие методы проверки пользователя.
Пример: клиент подключается к ws://localhost:8080?token=JWT_HERE, а сервер валидирует токен при апгрейде соединения.

import http from "http";
import WebSocket, { WebSocketServer } from "ws";
import jwt from "jsonwebtoken";
 
const server = http.createServer();
const wss = new WebSocketServer({ noServer: true });
 
// апгрейд соединения с аутентификацией
server.on("upgrade", (req, socket, head) => {
  try {
    const url = new URL(req.url, `http://${req.headers.host}`);
    const token = url.searchParams.get("token");
 
    if (!token) throw new Error("No token provided");
 
	// верификация JWT-токена
    jwt.verify(token, "your-secret-key", (err, decoded) => {
      if (err) {
        socket.write("HTTP/1.1 401 Unauthorized\r\n\r\n");
        socket.destroy();
        return;
      }
	  // посылаем WebSocket-хэндшейк
      wss.handleUpgrade(req, socket, head, (ws) => {
        ws.user = decoded;
        wss.emit("connection", ws, req);
      });
    });
  } catch {
    socket.write("HTTP/1.1 401 Unauthorized\r\n\r\n");
    socket.destroy();
  }
});
 
wss.on("connection", (ws) => {
  ws.send("Добро пожаловать! Аутентификация прошла успешно ✅");
});
 
server.listen(8080);

В примере создаётся обычный HTTP-сервер:

const server = http.createServer();
const wss = new WebSocketServer({ noServer: true });

Почему так?

  • HTTP-сервер слушает порт и принимает все входящие соединения.
  • Параметр noServer: true говорит, что WebSocket-сервер сам порт не открывает.
  • Вместо этого мы вручную перехватываем запросы на апгрейд (server.on('upgrade')), проверяем токен и только потом передаём соединение в wss.handleUpgrade(...).

Такой подход позволяет объединить обычные HTTP-запросы и WebSocket-подключения на одном порту и встроить аутентификацию прямо в процесс апгрейда.

Rate limiting (ограничение частоты сообщений)

Чтобы избежать спама и DoS-атак, ограничивайте количество сообщений от клиента.

import rateLimit from "ws-rate-limit";
 
const limiter = rateLimit({
  windowMs: 60 * 1000, // 1 минута
  max: 100, // не более 100 сообщений
  message: "Слишком много сообщений, замедлитесь!",
});
 
wss.on("connection", (ws) => {
  limiter(ws);
  ws.on("message", (msg) => {
    console.log("Получено:", msg.toString());
  });
});

Где применять WebSockets

  • Чаты и мессенджеры
  • Онлайн-игры
  • Финансовые системы (котировки, биржевые данные)
  • Совместное редактирование документов
  • Live-уведомления (например, новые комментарии или лайки)

Альтернативы

В ряде случаев вместо WebSockets можно использовать Server-Sent Events (SSE) или WebRTC (для P2P-связи). Но WebSockets — наиболее универсальное решение для большинства задач real-time.

Итог

WebSocket — это современный способ устанавливать постоянное соединение между браузером и сервером.

  • У WebSocket нет ограничений по кросс-доменным запросам.
  • Поддержка во всех популярных браузерах.
  • Можно передавать как строки, так и бинарные данные.
  • API очень простой.

Методы:

  • socket.send(data)
  • socket.close([code], [reason])

События:

  • open
  • message
  • error
  • close

Однако сам по себе WebSocket не включает механизмы повторного подключения, аутентификации и другие высокоуровневые возможности. Для этого существуют клиентские/серверные библиотеки, но также можно реализовать всё вручную.

10 минут чтения
Средний рейтинг статьи — 4.9

Настроить мониторинг за 30 секунд

Надежные оповещения о даунтаймах. Без ложных срабатываний