WebSocket на TypeScript: real-time приложения от А до Я

Онлайн-тренажер Python для начинающих

Изучайте Python легко и без перегрузки теорией. Решайте практические задачи с автоматической проверкой, получайте подсказки на русском языке и пишите код прямо в браузере — без необходимости что-либо устанавливать.

Начать курс

Введение в WebSocket и TypeScript для real-time приложений

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

В сочетании с TypeScript — строго типизированным надмножеством JavaScript — разработка WebSocket-приложений становится не только эффективной, но и безопасной. TypeScript позволяет выявлять ошибки на этапе компиляции, улучшает читаемость кода и упрощает рефакторинг. В этой статье мы разберём полный цикл создания real-time приложения на WebSocket с TypeScript: от теории до практических примеров.

Основы WebSocket: как работает протокол

Что такое WebSocket?

WebSocket (RFC 6455) — это протокол, который устанавливает постоянное соединение между клиентом (браузером) и сервером. После рукопожатия (handshake) данные могут передаваться в обоих направлениях без повторных HTTP-запросов. Это снижает задержки и нагрузку на сеть.

Отличие от HTTP

  • HTTP: клиент инициирует запрос → сервер отвечает → соединение закрывается (или остаётся открытым для следующих запросов, но всё равно инициируется клиентом).
  • WebSocket: после установки соединения сервер может отправлять данные клиенту в любой момент (push-уведомления).

Жизненный цикл WebSocket-соединения

  1. Рукопожатие (Handshake): клиент отправляет HTTP-запрос с заголовком Upgrade: websocket. Сервер отвечает кодом 101 Switching Protocols.
  2. Обмен данными: после успешного рукопожатия соединение переключается на WebSocket-протокол. Данные передаются в виде фреймов.
  3. Закрытие: любая из сторон может инициировать закрытие соединения, отправив специальный управляющий фрейм.

Создание WebSocket-сервера на TypeScript

Выбор библиотеки

Для серверной части мы будем использовать популярную библиотеку ws — легковесную и быструю реализацию WebSocket для Node.js. Установим её вместе с типами для TypeScript:

npm install ws
npm install -D @types/ws

Базовый сервер

Создадим файл server.ts:

import { WebSocketServer, WebSocket } from 'ws';

const PORT = 8080;
const wss = new WebSocketServer({ port: PORT });

console.log(`WebSocket сервер запущен на ws://localhost:${PORT}`);

wss.on('connection', (ws: WebSocket) => {
  console.log('Новое подключение');

  // Отправляем приветственное сообщение
  ws.send('Добро пожаловать на сервер!');

  // Обработка входящих сообщений
  ws.on('message', (message: Buffer) => {
    const text = message.toString();
    console.log(`Получено: ${text}`);

    // Эхо-ответ
    ws.send(`Эхо: ${text}`);
  });

  // Обработка закрытия соединения
  ws.on('close', () => {
    console.log('Клиент отключился');
  });

  // Обработка ошибок
  ws.on('error', (error: Error) => {
    console.error('Ошибка WebSocket:', error);
  });
});

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

В реальных приложениях сообщения часто структурированы в формате JSON. Создадим типизированный обработчик:

interface ChatMessage {
  type: 'message' | 'join' | 'leave';
  username: string;
  content?: string;
  timestamp: number;
}

wss.on('connection', (ws: WebSocket) => {
  ws.on('message', (data: Buffer) => {
    try {
      const msg: ChatMessage = JSON.parse(data.toString());
      
      switch (msg.type) {
        case 'join':
          console.log(`${msg.username} присоединился к чату`);
          broadcast({ type: 'system', content: `${msg.username} вошёл в чат` });
          break;
        case 'message':
          broadcast(msg);
          break;
        default:
          ws.send(JSON.stringify({ error: 'Неизвестный тип сообщения' }));
      }
    } catch (e) {
      ws.send(JSON.stringify({ error: 'Некорректный JSON' }));
    }
  });
});

function broadcast(message: object): void {
  wss.clients.forEach((client) => {
    if (client.readyState === WebSocket.OPEN) {
      client.send(JSON.stringify(message));
    }
  });
}

Клиентская часть: WebSocket в браузере на TypeScript

Подключение к серверу

Создадим файл client.ts для браузерного окружения:

const WS_URL = 'ws://localhost:8080';
let socket: WebSocket;

function connect(): void {
  socket = new WebSocket(WS_URL);

  socket.onopen = () => {
    console.log('Соединение установлено');
    // Отправляем сообщение о входе
    sendMessage({ type: 'join', username: 'User123', timestamp: Date.now() });
  };

  socket.onmessage = (event: MessageEvent) => {
    const data = JSON.parse(event.data);
    console.log('Получено сообщение:', data);
    // Здесь можно обновить UI
  };

  socket.onclose = () => {
    console.log('Соединение закрыто');
    // Попробовать переподключиться через 3 секунды
    setTimeout(connect, 3000);
  };

  socket.onerror = (error: Event) => {
    console.error('Ошибка WebSocket:', error);
  };
}

function sendMessage(msg: object): void {
  if (socket.readyState === WebSocket.OPEN) {
    socket.send(JSON.stringify(msg));
  } else {
    console.warn('Соединение не открыто');
  }
}

connect();

Типизация событий

Для улучшения типизации создадим обёртку:

type MessageHandler = (data: ChatMessage) => void;

class TypedWebSocket {
  private ws: WebSocket;

  constructor(url: string) {
    this.ws = new WebSocket(url);
  }

  onMessage(handler: MessageHandler): void {
    this.ws.onmessage = (event) => {
      const data: ChatMessage = JSON.parse(event.data);
      handler(data);
    };
  }

  sendMessage(msg: ChatMessage): void {
    this.ws.send(JSON.stringify(msg));
  }

  close(): void {
    this.ws.close();
  }
}

// Использование
const client = new TypedWebSocket('ws://localhost:8080');
client.onMessage((                

Блоги

Рекомендаций по книгам