PurpleSchool — курсы программирования онлайн
  • Бесплатно
    • Курсы
    • JavaScript Основы разработкиPython Основы PythonCSS CSS FlexboxКарта развития
    • База знанийИконка стрелки
    • Новостные рассылкиИконка стрелки
  • Пути
    • Frontend React разработчик
    • Frontend Vue разработчик
    • Backend разработчик Node.js
    • Fullstack разработчик React / Node.js
    • Mobile разработчик React Native
    • Backend разработчик Golang
    • Devops инженер
    • Backend разработчик Python
  • AI для кодаНовое
  • О нас
    • Отзывы
    • Реферальная программа
    • О компании
    • Контакты
  • Иконка открытия меню
    • Сообщество
    • PurpleПлюс
    • AI тренажёр
    • Проекты
PurpleSchool — платформа бесплатных roadmap и курсов для разработчиков
ютуб иконка
Telegram иконка
VK иконка
VK иконка
Курсы
ГлавнаяКаталог курсовFrontendBackendFullstack
Практика
КарьераПроектыPurpleПлюс
Материалы
БлогБаза знаний
Документы
Договор офертаПолитика конфиденциальностиПроверка сертификатаМиграция курсовРеферальная программа
Реквизиты
ИП Ларичев Антон АндреевичИНН 773373765379contact@purpleschool.ru

PurpleSchool © 2020 -2026 Все права защищены

  • Курсы
    • FrontendИконка стрелки
    • AI разработкаИконка стрелки
    • BackendИконка стрелки
    • DevOpsИконка стрелки
    • MobileИконка стрелки
    • ТестированиеИконка стрелки
    • Soft-skillsИконка стрелки
    • ДизайнИконка стрелки
    Иконка слояПерейти в каталог курсов
  • PurpleSchool — курсы программирования онлайн
    • AI для кодаНовое
    • Сообщество
    • PurpleПлюс
    • AI тренажёр
    • Проекты
    Главная
    Сообщество
    WebSocket на Node.js: строим real-time чат с нуля за час

    WebSocket на Node.js: строим real-time чат с нуля за час

    Аватар автора WebSocket на Node.js: строим real-time чат с нуля за час

    Антон Ларичев

    Иконка календаря26 мая 2026
    Node.jsWebSocketJavaScriptReal-timeBackendmiddleИконка уровня middle
    Картинка поста WebSocket на Node.js: строим real-time чат с нуля за час

    Введение

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

    В этой статье мы построим полноценный real-time чат на Node.js с использованием библиотеки ws. Разберём подключение клиентов, broadcast-рассылку, обработку отключений и типичные ошибки, которые подстерегают разработчиков.

    Установка зависимостей

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

    mkdir realtime-chat && cd realtime-chat
    npm init -y
    npm install ws
    

    Для разработки удобно использовать nodemon, чтобы сервер перезапускался автоматически при изменениях.

    npm install --save-dev nodemon
    

    Минимальный WebSocket-сервер

    Начнём с базового сервера, который принимает подключения и отвечает на сообщения. Создаём файл server.js.

    const { WebSocketServer } = require('ws');
    
    // Создаём сервер на порту 8080
    const wss = new WebSocketServer({ port: 8080 });
    
    wss.on('connection', (ws) => {
      console.log('Новый клиент подключился');
    
      // Обработчик входящих сообщений от клиента
      ws.on('message', (data) => {
        const message = data.toString();
        console.log('Получено:', message);
        ws.send(`Эхо: ${message}`);
      });
    
      // Уведомление об отключении клиента
      ws.on('close', () => {
        console.log('Клиент отключился');
      });
    });
    
    console.log('Сервер запущен на ws://localhost:8080');
    

    Запускаем командой node server.js. Сервер слушает порт 8080 и пересылает каждому клиенту его же сообщение с префиксом.

    Broadcast: рассылаем сообщения всем

    Чат отличается от эха тем, что сообщение от одного пользователя должно прийти всем остальным. Реализуем broadcast через коллекцию wss.clients.

    const { WebSocketServer, WebSocket } = require('ws');
    
    const wss = new WebSocketServer({ port: 8080 });
    
    function broadcast(sender, message) {
      // Перебираем всех подключённых клиентов
      wss.clients.forEach((client) => {
        // Шлём только активным соединениям и не отправителю
        if (client !== sender && client.readyState === WebSocket.OPEN) {
          client.send(message);
        }
      });
    }
    
    wss.on('connection', (ws) => {
      ws.on('message', (data) => {
        broadcast(ws, data.toString());
      });
    });
    

    Проверка readyState === WebSocket.OPEN критична: соединение может быть в процессе закрытия, и отправка вызовет ошибку.

    Структурированные сообщения

    Голый текст быстро становится узким местом. Перейдём на JSON-формат с типами событий: подключение пользователя, чат-сообщение, выход.

    wss.on('connection', (ws) => {
      // Сохраняем имя пользователя прямо на объекте соединения
      ws.username = `User${Math.floor(Math.random() * 1000)}`;
    
      // Уведомляем остальных о новом участнике
      broadcast(ws, JSON.stringify({
        type: 'join',
        user: ws.username,
        timestamp: Date.now()
      }));
    
      ws.on('message', (raw) => {
        try {
          const payload = JSON.parse(raw.toString());
          if (payload.type === 'chat') {
            broadcast(ws, JSON.stringify({
              type: 'chat',
              user: ws.username,
              text: payload.text,
              timestamp: Date.now()
            }));
          }
        } catch (err) {
          // Игнорируем некорректный JSON, чтобы не крашить сервер
          console.error('Невалидное сообщение:', err.message);
        }
      });
    });
    

    Heartbeat: ловим зависшие соединения

    TCP не всегда замечает разрыв связи — клиент может уйти в спящий режим, и сервер будет считать его активным. Решение — ping/pong с интервалом.

    function heartbeat() {
      this.isAlive = true;
    }
    
    wss.on('connection', (ws) => {
      ws.isAlive = true;
      ws.on('pong', heartbeat);
    });
    
    // Каждые 30 секунд проверяем живость клиентов
    const interval = setInterval(() => {
      wss.clients.forEach((ws) => {
        if (ws.isAlive === false) return ws.terminate();
        ws.isAlive = false;
        ws.ping();
      });
    }, 30000);
    
    wss.on('close', () => clearInterval(interval));
    

    Клиент в браузере

    Для тестирования напишем минимальный HTML-клиент. Он подключается к серверу и обменивается JSON-сообщениями.

    <!DOCTYPE html>
    <html>
    <body>
      <input id="msg" placeholder="Сообщение" />
      <button onclick="send()">Отправить</button>
      <ul id="log"></ul>
      <script>
        const ws = new WebSocket('ws://localhost:8080');
    
        ws.onmessage = (event) => {
          const data = JSON.parse(event.data);
          const li = document.createElement('li');
          li.textContent = `${data.user}: ${data.text}`;
          document.getElementById('log').appendChild(li);
        };
    
        function send() {
          const input = document.getElementById('msg');
          ws.send(JSON.stringify({ type: 'chat', text: input.value }));
          input.value = '';
        }
      </script>
    </body>
    </html>
    

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

    Отправка в закрытое соединение. Вызов ws.send() на соединении со статусом CLOSING или CLOSED бросает исключение. Всегда проверяйте readyState перед отправкой.

    Отсутствие обработки ошибок парсинга. Один невалидный JSON от вредоносного клиента уронит весь сервер, если парсинг не обёрнут в try/catch.

    Игнорирование backpressure. Если клиент медленный, буфер bufferedAmount растёт и съедает память. Проверяйте его и при переполнении закрывайте соединение или дропайте сообщения.

    Хранение состояния в памяти процесса. При горизонтальном масштабировании клиенты на разных нодах не увидят друг друга. Используйте Redis Pub/Sub или специализированные брокеры.

    Отсутствие аутентификации. WebSocket не проверяет origin и токены автоматически. Валидируйте JWT в обработчике upgrade HTTP-сервера до апгрейда протокола.

    Заключение

    Мы построили рабочий real-time чат на Node.js с поддержкой broadcast, структурированных сообщений и heartbeat-проверок. Библиотека ws даёт низкоуровневый контроль и минимальные накладные расходы, что делает её отличной основой для продакшен-решений.

    Следующие шаги: добавьте аутентификацию через JWT, персистентность сообщений в базу данных, комнаты/каналы и горизонтальное масштабирование через Redis. Для более высокоуровневого API рассмотрите Socket.IO — он умеет автоматический reconnect и fallback на long-polling, но платит за это размером и оверхедом.

    Иконка глаза6

    Комментарии

    0

    Постройте личный план изучения JavaScript с нуля - основы языка и практика для начинающих до уровня Middle — бесплатно!

    JavaScript с нуля - основы языка и практика для начинающих — часть карты развития Frontend, Backend, Mobile

    • step100+ шагов развития
    • lessons30 бесплатных лекций
    • lessons300 бонусных рублей на счет

    Бесплатные лекции

    Лучшие курсы по теме

    изображение курса

    Продвинутый JavaScript

    Антон Ларичев
    AI-тренажерыAI-тренажеры
    Практика в студииПрактика в студии
    Гарантия
    Бонусы
    иконка звёздочки рейтинга4.8
    3 999 ₽ 6 990 ₽
    Подробнее
    изображение курса

    TypeScript с нуля

    Антон Ларичев
    AI-тренажерыAI-тренажеры
    Практика в студииПрактика в студии
    Гарантия
    Бонусы
    иконка звёздочки рейтинга4.8
    3 999 ₽ 6 990 ₽
    Подробнее
    изображение курса

    React и Redux Toolkit

    Антон Ларичев
    AI-тренажерыAI-тренажеры
    Практика в студииПрактика в студии
    Гарантия
    Бонусы
    иконка звёздочки рейтинга4.8
    3 999 ₽ 6 990 ₽
    Подробнее

    Похожие статьи

    Картинка поста REST API на Node.js и Express: пишем сервер с нуля за час
    Иконка аватараАнтон
    Иконка календаря08 мая 2026
    Node.jsExpressREST API+ 2juniorИконка уровня junior

    REST API на Node.js и Express: пишем сервер с нуля за час

    REST API на Node.js и Express: пошаговое руководство по созданию сервера с маршрутизацией, валидацией и обработкой ошибок.

    Иконка чипа0
    Иконка глаза269
    Иконка комментариев0
    Картинка поста Event Loop в Node.js: как работает и зачем это знать
    Иконка аватараАнтон
    Иконка календаря04 мая 2026
    Node.jsJavaScriptEvent Loop+ 2middleИконка уровня middle

    Event Loop в Node.js: как работает и зачем это знать

    Event Loop в Node.js — основа асинхронности. Разбираем фазы цикла событий, очереди задач и типичные ошибки на практических примерах.

    Иконка чипа0
    Иконка глаза270
    Иконка комментариев0
    Картинка поста Как настроить ESLint и Prettier в проекте раз и навсегда
    Иконка аватараАнтон
    Иконка календаря25 мая 2026
    ESLintPrettierJavaScript+ 2juniorИконка уровня junior

    Как настроить ESLint и Prettier в проекте раз и навсегда

    Настройка ESLint и Prettier в проекте: пошаговое руководство по интеграции линтера и форматтера без конфликтов, с автоформатированием в VS Code и Git-хуками.

    Иконка чипа0
    Иконка глаза46
    Иконка комментариев0
    Иконка чипа0