WebSocket на TypeScript: Создаем real-time приложения
Современные веб-приложения все чаще требуют мгновенной передачи данных между клиентом и сервером. Технология WebSocket стала стандартом для создания real-time приложений — от чатов и уведомлений до онлайн-игр и торговых платформ. В этой статье мы разберем, как использовать WebSocket на TypeScript, и покажем примеры кода для создания полноценного real-time приложения.
Что такое WebSocket и почему TypeScript?
WebSocket — это протокол, обеспечивающий постоянное двунаправленное соединение между клиентом и сервером. В отличие от HTTP, где клиент отправляет запрос и получает ответ, WebSocket позволяет обеим сторонам инициировать передачу данных в любой момент. Это идеально подходит для real-time приложений, где важна низкая задержка.
TypeScript добавляет к JavaScript статическую типизацию, что критически важно для проектов с WebSocket. Типы помогают избежать ошибок при обработке сообщений и делают код более предсказуемым. Например, вы можете определить интерфейс для входящих и исходящих сообщений:
interface ChatMessage {
type: 'message' | 'join' | 'leave';
user: string;
text?: string;
timestamp: number;
}
interface ServerResponse {
status: 'ok' | 'error';
data?: ChatMessage;
error?: string;
}
Такой подход значительно упрощает отладку и поддержку кода.
Настройка WebSocket сервера на TypeScript
Для создания сервера мы будем использовать библиотеку ws — популярную реализацию WebSocket для Node.js. Установим зависимости:
npm init -y
npm install ws @types/ws typescript @types/node
npx tsc --init
Создадим файл server.ts:
import { WebSocketServer, WebSocket } from 'ws';
const wss = new WebSocketServer({ port: 8080 });
wss.on('connection', (ws: WebSocket, req) => {
console.log('Новый клиент подключен');
// Отправляем приветственное сообщение
ws.send(JSON.stringify({
type: 'system',
message: 'Добро пожаловать в чат!'
}));
// Обрабатываем входящие сообщения
ws.on('message', (data: Buffer) => {
try {
const message = JSON.parse(data.toString());
console.log('Получено:', message);
// Рассылаем сообщение всем подключенным клиентам
wss.clients.forEach((client) => {
if (client.readyState === WebSocket.OPEN) {
client.send(JSON.stringify({
type: 'broadcast',
user: message.user,
text: message.text,
timestamp: Date.now()
}));
}
});
} catch (error) {
ws.send(JSON.stringify({
type: 'error',
message: 'Некорректный формат сообщения'
}));
}
});
ws.on('close', () => {
console.log('Клиент отключился');
});
});
console.log('WebSocket сервер запущен на ws://localhost:8080');
Запустите сервер командой npx ts-node server.ts. Сервер готов принимать подключения и транслировать сообщения.
WebSocket клиент на TypeScript
Теперь создадим клиентскую часть. TypeScript отлично работает в браузере, поэтому мы напишем клиент на чистом TypeScript, который будет компилироваться в JavaScript.
Файл client.ts:
interface ChatMessage {
type: string;
user?: string;
text?: string;
message?: string;
timestamp?: number;
}
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('Система', 'Пользователь вошел в чат');
};
this.socket.onmessage = (event: MessageEvent) => {
const data: ChatMessage = JSON.parse(event.data);
this.handleMessage(data);
};
this.socket.onclose = () => {
console.log('Соединение закрыто');
};
this.socket.onerror = (error: Event) => {
console.error('Ошибка WebSocket:', error);
};
}
private handleMessage(data: ChatMessage): void {
switch (data.type) {
case 'system':
console.log(`[Система] ${data.message}`);
break;
case 'broadcast':
console.log(`[${data.user}] ${data.text} (${new Date(data.timestamp!).toLocaleTimeString()})`);
break;
case 'error':
console.error(`[Ошибка] ${data.message}`);
break;
default:
console.log('Неизвестный тип сообщения:', data);
}
}
public sendMessage(user: string, text: string): void {
const message: ChatMessage = {
type: 'message',
user: user,
text: text
};
this.socket.send(JSON.stringify(message));
}
public disconnect(): void {
this.socket.close();
}
}
// Использование:
const client = new WebSocketClient('ws://localhost:8080');
Клиент автоматически подключается к серверу, обрабатывает различные типы сообщений и предоставляет удобный интерфейс для отправки данных.
Расширенные возможности: аутентификация и комнаты
Для создания полноценного real-time приложения часто требуется аутентификация и разделение на комнаты. Рассмотрим, как добавить эти функции.
Аутентификация через токен:
// Сервер
import { IncomingMessage } from 'http';
wss.on('connection', (ws: WebSocket, req: IncomingMessage) => {
const token = new URL(req.url!, `http://${req.headers.host}`).searchParams.get('token');
if (!token || !validateToken(token)) {
ws.close(4001, 'Недействительный токен');
return;
}
// Продолжаем обработку
});
// Клиент
const client = new WebSocketClient('ws://localhost:8080?token=ваш_токен');
Разделение на комнаты:
interface Room {
name: string;
clients: Set<WebSocket>;
}
const rooms: Map<string, Room> = new Map();
function joinRoom(ws: WebSocket, roomName: string): void {
if (!rooms.has(roomName)) {
rooms.set(roomName, { name: roomName, clients: new Set() });
}
rooms.get(roomName)!.clients.add(ws);
}
function broadcastToRoom(roomName: string, message: string, sender: WebSocket): void {
const room = rooms.get(roomName);
if (room) {
room.clients.forEach(client => {
if (client !== sender && client.readyState === WebSocket.OPEN) {
client.send(message);
}
});
}
}
Эти улучшения позволяют создавать масштаби