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()
}));
}