WebSocket на JavaScript: создаем real-time приложения на Node.js

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

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

Начать курс

WebSocket на JavaScript: создаем real-time приложения на Node.js

Современный веб требует мгновенной реакции. Пользователи ожидают, что сообщения в чате доставляются за миллисекунды, котировки акций обновляются без перезагрузки страницы, а уведомления приходят в реальном времени. Технология WebSocket на JavaScript решает эту задачу, обеспечивая постоянное двустороннее соединение между клиентом и сервером. В этой статье мы разберем, как использовать WebSocket в среде Node.js для создания быстрых и масштабируемых real-time приложений.

Что такое WebSocket и зачем он нужен?

Традиционный HTTP-протокол работает по принципу "запрос-ответ": клиент отправляет запрос, сервер отвечает, соединение закрывается. Для получения новых данных клиенту приходится постоянно опрашивать сервер (polling) или использовать длинные HTTP-запросы (long polling). Это неэффективно, создает избыточную нагрузку и увеличивает задержку.

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

  • Чатов и мессенджеров
  • Онлайн-игр и совместного редактирования
  • Биржевых котировок и финансовых дашбордов
  • Push-уведомлений и мониторинга
  • Потоковой передачи данных (IoT, логи)

Установка и настройка сервера WebSocket на Node.js

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

npm install ws

Создадим простой WebSocket-сервер. Сначала импортируем модуль и создаём экземпляр сервера на порту 8080:

const WebSocket = require('ws');

const wss = new WebSocket.Server({ port: 8080 });

wss.on('connection', function connection(ws) {
    console.log('Новый клиент подключился');

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

    // Обрабатываем входящие сообщения
    ws.on('message', function incoming(message) {
        console.log('Получено: %s', message);
        // Отвечаем всем подключенным клиентам
        wss.clients.forEach(function each(client) {
            if (client.readyState === WebSocket.OPEN) {
                client.send(`Эхо: ${message}`);
            }
        });
    });

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

    // Обрабатываем ошибки
    ws.on('error', function error(err) {
        console.error('Ошибка WebSocket:', err);
    });
});

console.log('WebSocket сервер запущен на ws://localhost:8080');

Этот код создает простой эхо-сервер: любое сообщение, отправленное клиентом, будет разослано всем подключенным пользователям. Обратите внимание на проверку readyState — она гарантирует, что мы не пытаемся отправить данные в закрытое соединение.

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

На стороне клиента (браузера) WebSocket является встроенным объектом — никаких дополнительных библиотек не требуется. Подключимся к нашему серверу и реализуем простой чат:

// Создаем WebSocket соединение
const socket = new WebSocket('ws://localhost:8080');

// Обработчик открытия соединения
socket.addEventListener('open', function (event) {
    console.log('Соединение установлено');
    socket.send('Привет, сервер!');
});

// Обработчик получения сообщения
socket.addEventListener('message', function (event) {
    const messagesDiv = document.getElementById('messages');
    const messageElement = document.createElement('div');
    messageElement.textContent = event.data;
    messagesDiv.appendChild(messageElement);
});

// Обработчик ошибок
socket.addEventListener('error', function (event) {
    console.error('Ошибка WebSocket:', event);
});

// Обработчик закрытия соединения
socket.addEventListener('close', function (event) {
    console.log('Соединение закрыто с кодом:', event.code);
});

// Функция отправки сообщения из формы
function sendMessage() {
    const input = document.getElementById('messageInput');
    if (input.value) {
        socket.send(input.value);
        input.value = '';
    }
}

HTML-структура для этого чата может выглядеть так:

<div id="messages" style="height: 300px; overflow-y: scroll; border: 1px solid #ccc;"></div>
<input type="text" id="messageInput" placeholder="Введите сообщение" />
<button onclick="sendMessage()">Отправить</button>

Важно помнить: WebSocket использует протокол ws:// (или wss:// для защищенного соединения через TLS). В продакшене всегда используйте wss://.

Разработка полноценного чата: управление комнатами и пользователями

Простой эхо-сервер — это только начало. Давайте создадим более функциональное приложение: чат с поддержкой комнат и имен пользователей. Для этого нам понадобится хранить метаданные о каждом подключении.

Модифицируем сервер, добавив поддержку комнат:

const WebSocket = require('ws');

const wss = new WebSocket.Server({ port: 8080 });

// Хранилище комнат: { roomName: Set of clients }
const rooms = new Map();

wss.on('connection', function connection(ws) {
    let userName = 'Аноним';
    let currentRoom = 'general';

    // Добавляем пользователя в общую комнату по умолчанию
    if (!rooms.has('general')) {
        rooms.set('general', new Set());
    }
    rooms.get('general').add(ws);

    // Отправляем пользователю список доступных команд
    ws.send(JSON.stringify({
        type: 'system',
        message: 'Добро пожаловать! Используйте: /nick [имя], /join [комната], /list'
    }));

    ws.on('message', function incoming(data) {
        const message = data.toString();

        // Обработка команд
        if (message.startsWith('/')) {
            handleCommand(ws, message, userName, currentRoom);
        } else {
            // Рассылаем сообщение всем в текущей комнате
            const room = rooms.get(currentRoom);
            if (room) {
                room.forEach(client => {
                    if (client.readyState === WebSocket.OPEN) {
                        client.send(JSON.stringify({
                            type: 'message',
                            user: userName,
                            text: message,
                            room: currentRoom,
                            timestamp: new Date().toISOString()
                        }));
                    }                

Блоги

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