Фото Кристофера Робіна Еббінгхауса на Unsplash
Вступ
Реальний час комунікації дозволяє клієнтам і серверам обмінюватися даними без необхідності постійно виконувати запити (polling). За допомогою WebSocket ми можемо створювати з'єднання, яке залишається активним, що дозволяє клієнту та серверу надсилати і отримувати повідомлення у будь-який час.
Приклад застосунків з комунікацією в реальному часі:
- Чат додатки: WhatsApp, Telegram або інші месенджери.
- Прямі сповіщення: Оновлення статусу замовлення в додатках електронної комерції.
- Спільна робота: Додатки, як Google Docs, для спільного редагування документів.
1. Що таке WebSocket?
1.1 Пояснення WebSocket
- WebSocket — це протокол зв'язку, заснований на TCP, що дозволяє двосторонню комунікацію між клієнтом та сервером.
- На відміну від HTTP, WebSocket використовує з'єднання, яке завжди активне, що робить його ідеальним для застосунків в реальному часі.
1.2 Різниця між WebSocket та HTTP
2. Початок роботи з WebSocket в Node.js
2.1 Встановлення та налаштування
- Встановіть бібліотеку WebSocket: Використовуйте бібліотеку
ws
для керування з'єднаннями WebSocket:
npm install ws
2. Створіть простий сервер WebSocket: Створіть файл server.js
:
const WebSocket = require('ws');
// Створити сервер WebSocket
const wss = new WebSocket.Server({ port: 8080 });
// Подія: коли клієнт підключається
wss.on('connection', (ws) => {
console.log('Клієнт підключений');
// Подія: коли сервер отримує повідомлення від клієнта
ws.on('message', (message) => {
console.log(`Повідомлення отримано: ${message}`);
// Відправити відповідь клієнту
ws.send(`Повідомлення "${message}" отримано на сервері`);
});
// Відправити повідомлення клієнту під час підключення
ws.send('Ласкаво просимо на сервер WebSocket');
});
console.log('Сервер WebSocket працює на ws://localhost:8080');
3. Пояснення:
wss.on('connection')
: Подія, що спрацьовує, коли клієнт підключається.ws.on('message')
: Подія для обробки повідомлень, отриманих від клієнта.ws.send()
: Використовується для відправлення повідомлень клієнту.
2.2 Тестування сервера WebSocket
- Використовуйте WebSocket клієнт у браузері:
Відкрийте консоль браузера (Developer Tools) і запустіть наступний код:
const ws = new WebSocket('ws://localhost:8080');
// Подія: коли з'єднання успішно встановлено
ws.onopen = () => {
console.log('Підключено до сервера WebSocket');
ws.send('Привіт від клієнта');
};
// Подія: коли повідомлення отримано від сервера
ws.onmessage = (event) => {
console.log('Повідомлення від сервера:', event.data);
};
// Подія: коли з'єднання закривається
ws.onclose = () => {
console.log('З'єднання WebSocket закрите');
};
2. Очікувані результати:
- Коли клієнт підключається, сервер відправляє повідомлення "Ласкаво просимо на сервер WebSocket".
- Коли клієнт надсилає повідомлення на сервер, сервер відповідає повідомленням "Повідомлення [вміст повідомлення] отримано на сервері".
3. WebSocket з Express
3.1 Об'єднання WebSocket з Express
1.
Створіть файл app.js
:
const express = require('express');
const http = require('http');
const WebSocket = require('ws');
const app = express();
const server = http.createServer(app); // HTTP сервер
const wss = new WebSocket.Server({ server }); // Об'єднайте WebSocket з HTTP сервером
// HTTP Endpoint
app.get('/', (req, res) => {
res.send('Сервер працює з WebSocket');
});
// Подія: коли клієнт підключається
wss.on('connection', (ws) => {
console.log('Клієнт підключений');
ws.on('message', (message) => {
console.log(`Повідомлення від клієнта: ${message}`);
ws.send(`Повідомлення "${message}" отримано сервером`);
});
});
// Запустіть сервер на порту 3000
server.listen(3000, () => {
console.log('Сервер працює на http://localhost:3000');
console.log('WebSocket працює на ws://localhost:3000');
});
4. Приклад використання: Простий чат додаток
4.1 Концепція додатку
Ми створимо простий чат додаток з наступними можливостями:
- Клієнт може відправляти повідомлення на сервер.
- Сервер поширює це повідомлення серед усіх підключених клієнтів.
4.2 Реалізація сервера чату
- Створення серверу чату: Додайте наступний код до
server.js
:
const clients = new Set(); // Зберігаємо список підключених клієнтів
wss.on('connection', (ws) => {
console.log('Клієнт підключений');
clients.add(ws); // Додаємо клієнта до списку
ws.on('message', (message) => {
console.log(`Повідомлення отримано: ${message}`);
// Розсилаємо повідомлення всім клієнтам
clients.forEach((client) => {
if (client !== ws && client.readyState === WebSocket.OPEN) {
client.send(message);
}
});
});
ws.on('close', () => {
console.log('Клієнт відключився');
clients.delete(ws); // Видаляємо клієнта зі списку
});
});
2. Пояснення:
- Set використовується для зберігання унікальних клієнтів.
client.send(message)
: Відправляє повідомлення всім клієнтам, окрім відправника.
4.3 Тестування чату
- Підключення кількох клієнтів:
Запустіть скрипт клієнта WebSocket в консолі браузера для кількох вкладок.
const ws = new WebSocket('ws://localhost:8080');
ws.onopen = () => {
ws.send('Повідомлення з вкладки 1');
};
ws.onmessage = (event) => {
console.log('Повідомлення отримано:', event.data);
};
2. Очікувані результати:
- Коли один клієнт відправляє повідомлення, всі інші клієнти отримують це повідомлення.
5. Оптимізація та безпека WebSocket
5.1 Аутентифікація у WebSocket
- Відправка токену під час підключення: Додайте токен аутентифікації в заголовки при підключенні клієнта:
const ws = new WebSocket('ws://localhost:8080', [], {
headers: { Authorization: 'Bearer ' },
});
2. Перевірка токену на сервері: Перевірте токен, коли клієнт підключається:
wss.on('connection', (ws, req) => {
const token = req.headers.authorization?.split(' ')[1];
if (!token || token !== 'VALID_TOKEN') {
ws.close(1008, 'Токен не дійсний'); // Закрити з'єднання, якщо токен недійсний
return;
}
console.log('Клієнт аутентифікований');
});
5.2 Лімітування запитів для WebSocket
Використовуйте алгоритм bucket для обмеження кількості повідомлень на клієнта:
const rateLimit = new Map();
wss.on('connection', (ws) => {
rateLimit.set(ws, { count: 0, timer: setInterval(() => rateLimit.get(ws).count = 0, 1000) });
ws.on('message', (message) => {
const clientRate = rateLimit.get(ws);
if (clientRate.count >= 5) {
ws.close(1008, 'Занадто багато повідомлень');
return;
}
clientRate.count += 1;
console.log('Повідомлення:', message);
});
ws.on('close', () => clearInterval(rateLimit.get(ws).timer));
});
6. Завдання та приклади використання
6.1 Завдання
- Додайте функцію імені користувача до чату.
- Реалізуйте аутентифікацію за допомогою JWT у WebSocket.
6.2 Приклад використання
- Створіть панель сповіщень в реальному часі, щоб оновлювати дані користувача при зміні з боку сервера.
7. Рефлексія та обговорення
1.
Питання для рефлексії:
- Які переваги WebSocket порівняно з HTTP для реальних додатків в реальному часі?
- Як ви забезпечуєте безпеку в додатках WebSocket?
2. Обговорення:
- Які виклики виникають при обробці великої кількості клієнтів одночасно?
- Як ви оптимізуєте продуктивність сервера WebSocket для великих масштабів?
Перекладено з: Node.js 8: WebSocket dan Komunikasi Real-Time