Берт и Эрни, два друга, работают над сторонним проектом своей мечты: приложением для чата, которое позволяет командам, работающим удаленно, общаться в режиме реального времени. Фронтенд-кодер Берт едва сдерживается, когда делится блестящими новыми функциями со своим другом-специалистом по бэкенду. «Смотри! Я могу набрать сообщение, и оно будет отправлено на сервер, и я вижу, как ответ появляется почти мгновенно!» Эрни, гуру бэкенда, хмурится. «Но как решить проблему, когда два человека пытаются общаться одновременно? Ваше приложение постоянно обновляет страницу вместо того, чтобы позволить вам «видеть» разговор, что делает невозможным общение в режиме реального времени».
Проблема в том, что приложение Берта работает на HTTP, в котором клиент должен запросить выборку с сервера. Эрни резюмирует: «Это как будто все ваши друзья пишут вам в ответ, но затем вы внезапно не видите ни одного ответа, пока не обновите страницу, чтобы проверить, есть ли новые сообщения, потому что они не видят ваше последнее сообщение, пока вы его не обновите, и именно так работает HTTP!»
А вот и самая лучшая часть: для полнофункциональных приложений, работающих в режиме реального времени, есть WebSockets. Эта часть очень захватывающая, поэтому давайте присоединимся к Эрни и Берту и узнаем, как работают WebSockets, каковы процедуры их внедрения, почему они так важны и многое другое.
WebSockets похожи на непрерывный телефонный звонок между клиентом (вашим веб-браузером) и сервером. Они отличаются от протокола HTTP, который работает по принципу «отправь письмо, жди ответа». С WebSockets обе стороны могут свободно общаться так, как им хочется. Возможности WebSockets включают в себя следующее:
Пример: Представьте себе постоянно обновляющееся спортивное табло. С HTTP клиент должен постоянно спамить сервер каждую секунду, «Есть ли изменения в счете?» С WebSockets сервер объявляет «ГОЛ!» в тот момент, когда это происходит.
Берт откидывается назад и чешет голову. «Но HTTP отлично работает для большинства приложений. Зачем менять правила игры?» Эрни тихо смеется, берет маркер и начинает что-то писать на доске.
«Начнем сверху», — говорит он. «Скажем, обновления в реальном времени, например, результаты спортивных матчей. Клиентам нужно каждую секунду спрашивать сервер: «Есть ли что-то, что мне нужно знать?» Это опрос, поэтому каждые тридцать секунд вам нужно спрашивать: «Мы встречаемся?». Смешно, не так ли? Это также использует большую пропускную способность».
WebSockets меняет ситуацию:
«HTTP довольно хорошо справляется со статическими вещами, такими как блог или страница продукта. Однако, когда дело доходит до живого взаимодействия, требуется постоянное соединение. WebSockets».
Эрни протирает очки. «Итак, давайте сделаем простое приложение для чата», — восклицает Эрни. «У нас будет сервер Node.js для бэкэнда и приложение React для фронтэнда. Готовы?»
«Возьмите сервер Node.js, потому что он вам понадобится для части Socket.IO», — говорит Эрни, печатая очень быстро:
npm init -y npm install express socket.io
Код сервера (server.js):
const express = require('express'); const http = require('http'); const { Server } = require('socket.io'); const app = express(); const server = http.createServer(app); const io = new Server(server); // Serve static files (like React's build folder) app.use(express.static('public')); // Handle WebSocket connections io.on('connection', (socket) => { console.log('New user connected:', socket.id); // Listen for Incoming messages from the socket socket.on('sendMessage', (message) => { console.log('Received:', message); // Broadcast the message to everyone io.emit('receiveMessage', message); }); // Handle user disconnects events socket.on('disconnect', () => { console.log('User left:', socket.id); }); }); server.listen(3000, () => { console.log('Visit http://localhost:3000 on a browser, Server started successful on port 3000'); });
«Клиент и сервер могут общаться друг с другом благодаря обработке соединений WebSocket в Socket.IO. Когда клиент вызывает функцию (sendMessage), сервер отправляет сообщение всем, кто подключен через (io.emit). Довольно просто, не правда ли?»
«Теперь моя очередь. Давайте приступим к работе над клиентом React», — говорит Берт.
npx create-react-app chat-client cd chat-client npm install socket.io-client
Компонент чата (Chat.js):
import { useState, useEffect } from 'react'; import io from 'socket.io-client'; // Connect to the server const socket = io('http://localhost:3000'); function Chat() { const [message, setMessage] = useState(''); const [messages, setMessages] = useState([]); useEffect(() => { // Listen for new messages socket.on('receiveMessage', (newMessage) => { setMessages([...messages, newMessage]); }); }, [messages]); const sendMessage = () => { if (message.trim()) { socket.emit('sendMessage', message); setMessage(''); } }; return ( <div style={{ padding: '20px' }}> <div> {messages.map((msg, index) => ( <p key={index}>{msg}</p> ))} </div> <input value={message} onChange={(e) => setMessage(e.target.value)} onKeyPress={(e) => e.key === 'Enter' && sendMessage()} /> <button onClick={sendMessage}>Send</button> </div> ); } export default Chat;
Как это работает:
Проверьте это:
Это то, что Берт намеревался построить на основе приложения, но Эрни упоминает: «Большинству реальных приложений требуется некоторая обработка ошибок и способ расширения фреймворка для разработки». Давайте рассмотрим некоторые вероятные проблемы.
Реализуйте стратегию повторного подключения в клиенте React.
socket.on('disconnect', () => { console.log('Disconnected. Trying to reconnect...'); socket.connect(); // Auto-reconnect });
Безопасный WebSocket с использованием аутентифицированных токенов JWT.
// On login, send a token socket.emit('authenticate', { token: 'USER_JWT' }); // Server verifies token socket.on('authenticate', ({ token }) => { if (isValidToken(token)) { socket.authenticated = true; } else { socket.disconnect(); } });
Внедрить передачу сообщений между различными серверами с использованием Redis.
npm install redis
Код сервера:
const redis = require('redis'); const subscriber = redis.createClient(); subscriber.subscribe('chat-channel'); subscriber.on('message', (channel, message) => { io.emit('receiveMessage', message); });
Beyond Chat: Редактирование общего документа
Это следующая идея Берта — редактор, похожий на Google Docs. Эрни говорит: «Вы можете использовать веб-сокеты, чтобы прослушивать изменения, вносимые разными людьми, и объединять их».
Например :
Пользователь А печатает: «Привет»
Пользователь B удаляет «o» и добавляет «, World»
Сервер прослушивает каждое нажатие клавиши и транслирует его всем клиентам, чтобы они могли отобразить ОБНОВЛЕННЫЙ документ.
Фрагмент кода:
// Client sends keystrokes textarea.addEventListener('input', (e) => { socket.emit('textChange', e.target.value); }); // Server broadcasts changes socket.on('textChange', (text) => { io.emit('updateText', text); });
Эрни предупреждает нас: «Никогда не используйте WebSockets без HTTPS/WSS!»
const io = new Server(server, { cors: { origin: "https://yourdomain.com" }, });
Проверяйте все входные данные, чтобы исключить любые данные, которые могут привести к XSS-атакам.
Установить ограничение на количество пользователей, рассылающих спам.
В: Скорость WebSockets намного выше, чем у HTTP?
A: Да! Для мгновенных приложений WebSockets являются лучшими, поскольку они устраняют необходимость проводить опрос.
В: Возможно ли использовать REST API вместе с WebSockets?
A: Да, определенно! Используйте WebSockets с обновлениями в реальном времени и REST для выполнения операций CRUD.
В: Что делать в случае сбоя сервера?
A: Клиенты могут автоматически переподключаться (см. логику переподключения выше).
Чат-приложение Берта теперь пингуется с очарованием в реальном времени, и Эрни улыбается от удовольствия. WebSockets не только для чатов, но и служат целям живых панелей управления, игр, IoT и многого другого.
Ваша очередь: Продолжайте и пробуйте примеры, разрушайте их и создавайте что-то новое. Ваши приложения реального времени ждут!