WebSocket на TypeScript: создание real-time приложений
Современные веб-приложения требуют мгновенного обмена данными между клиентом и сервером. Протокол WebSocket предоставляет постоянное двустороннее соединение, что делает его идеальным для создания чатов, систем уведомлений, онлайн-игр и других real-time сервисов. В этой статье мы подробно разберем, как работать с WebSocket на TypeScript — от настройки сервера до реализации клиента.
Что такое WebSocket и зачем он нужен?
WebSocket — это протокол связи, который обеспечивает полнодуплексный канал поверх одного TCP-соединения. В отличие от традиционного HTTP, где клиент отправляет запрос и ждет ответ, WebSocket позволяет серверу самостоятельно инициировать отправку данных клиенту.
Основные преимущества WebSocket:
- Постоянное соединение — не нужно устанавливать новое соединение для каждого запроса
- Низкая задержка — данные передаются мгновенно без оверхэда HTTP-заголовков
- Двусторонняя связь — сервер может отправлять данные без запроса от клиента
- Эффективность — меньше трафика по сравнению с polling-решениями
WebSocket широко применяется в финансовых приложениях (биржевые котировки), социальных сетях (лайки, комментарии в реальном времени), многопользовательских играх, системах мониторинга и IoT.
Настройка WebSocket сервера на TypeScript
Для создания сервера мы будем использовать популярную библиотеку ws. Установите ее через npm:
npm init -y
npm install ws
npm install -D typescript @types/ws @types/node
npx tsc --init
Создадим файл server.ts:
import { WebSocketServer, WebSocket } from 'ws';
const PORT = 8080;
const wss = new WebSocketServer({ port: PORT });
interface CustomMessage {
type: string;
payload: any;
}
wss.on('connection', (ws: WebSocket) => {
console.log('Новый клиент подключился');
// Отправляем приветственное сообщение
const welcomeMessage: CustomMessage = {
type: 'welcome',
payload: { message: 'Добро пожаловать на сервер!' }
};
ws.send(JSON.stringify(welcomeMessage));
// Обработка входящих сообщений
ws.on('message', (data: Buffer) => {
try {
const message: CustomMessage = JSON.parse(data.toString());
switch (message.type) {
case 'chat':
// Рассылаем сообщение всем подключенным клиентам
broadcast(message, ws);
break;
case 'ping':
ws.send(JSON.stringify({ type: 'pong', payload: {} }));
break;
default:
console.log('Неизвестный тип сообщения:', message.type);
}
} catch (error) {
console.error('Ошибка обработки сообщения:', error);
}
});
ws.on('close', () => {
console.log('Клиент отключился');
});
ws.on('error', (error: Error) => {
console.error('Ошибка WebSocket:', error);
});
});
function broadcast(message: CustomMessage, sender: WebSocket) {
wss.clients.forEach((client) => {
if (client !== sender && client.readyState === WebSocket.OPEN) {
client.send(JSON.stringify(message));
}
});
}
console.log(`WebSocket сервер запущен на ws://localhost:${PORT}`);
Запустите сервер командой npx ts-node server.ts. Сервер будет слушать порт 8080 и обрабатывать входящие соединения.
Создание WebSocket клиента на TypeScript
Клиентскую часть можно реализовать как для браузера, так и для Node.js. Рассмотрим оба варианта.
Браузерный клиент
Создадим файл client.ts для использования в веб-приложении:
class WebSocketClient {
private socket: WebSocket;
private url: string;
constructor(url: string) {
this.url = url;
this.socket = new WebSocket(url);
this.init();
}
private init(): void {
this.socket.onopen = () => {
console.log('Соединение установлено');
this.sendMessage('ping', {});
};
this.socket.onmessage = (event: MessageEvent) => {
const message = JSON.parse(event.data);
switch (message.type) {
case 'welcome':
console.log('Сервер:', message.payload.message);
break;
case 'chat':
this.displayMessage(message.payload);
break;
case 'pong':
console.log('Сервер ответил на ping');
break;
default:
console.log('Получено сообщение:', message);
}
};
this.socket.onclose = () => {
console.log('Соединение закрыто');
};
this.socket.onerror = (error: Event) => {
console.error('Ошибка WebSocket:', error);
};
}
public sendMessage(type: string, payload: any): void {
if (this.socket.readyState === WebSocket.OPEN) {
const message = JSON.stringify({ type, payload });
this.socket.send(message);
} else {
console.error('Соединение не открыто');
}
}
private displayMessage(payload: any): void {
// Здесь может быть логика отображения в UI
console.log('Сообщение:', payload);
}
public close(): void {
this.socket.close();
}
}
// Использование
const client = new WebSocketClient('ws://localhost:8080');
client.sendMessage('chat', { text: 'Привет всем!' });
Node.js клиент
Для серверного клиента используем библиотеку ws:
import WebSocket from 'ws';
const ws = new WebSocket('ws://localhost:8080');
ws.on('open', () => {
console.log('Подключено к серверу');
// Отправляем тестовое сообщение
ws.send(JSON.stringify({
type: 'chat',
payload: { text: 'Привет от Node.js клиента!' }
}));
});
ws.on('message', (data: WebSocket.Data) => {
const message = JSON.parse(data.toString());
console.log('Получено:', message);
});
ws.on('close', () => {
console.log('Соединение закрыто');
});
Практический пример: real-time чат
Соберем полноценное приложение чата с использованием TypeScript. Создадим структуру проекта:
chat-app/
├── server/
│ ├── server.ts
│ └── types.ts
├── client/
│ ├── index.html
│ └── client.ts
└── package.json
Файл types.ts для общих типов:
export interface ChatMessage {
username: string;
text: string;
timestamp: number;
}
export interface WSMessage {
type: 'chat' | 'join' | 'leave' | 'users';
payload: ChatMessage | string[] | { username: string };
}
Обновленный сер