Uvod: Kada HTTP nije dovoljan
Zajedno, Bert i Ernie, dva prijatelja, rade na sporednom projektu svojih snova: aplikaciji za chat koja omogućuje razgovore u stvarnom vremenu za timove koji rade na daljinu. Front-end koder Bert jedva se može suzdržati dok dijeli sjajne nove značajke sa svojim prijateljem specijalistom za backend. "Izgled! Mogu utipkati poruku i ona se šalje na poslužitelj, a ja mogu vidjeti odgovor koji iskače gotovo trenutno!” Ernie, backend guru, mršti se. “Ali kako riješiti problem dvoje ljudi koji pokušavaju razgovarati u isto vrijeme? Vaša aplikacija neprestano osvježava stranicu umjesto da vam dopusti da 'vidite' razgovor, što onemogućuje razgovor u stvarnom vremenu.”
Izazov je u tome što Bertova aplikacija radi na HTTP-u u kojem klijent mora zatražiti dohvaćanje s poslužitelja. Ernie sažima: "Kao da ti svi tvoji prijatelji uzvraćaju poruke, ali onda, iznenada, ne možeš vidjeti nijedan odgovor dok ne osvježiš da provjeriš ima li novih poruka jer oni ne mogu vidjeti tvoju posljednju poruku dok je ne osvježiš, a HTTP tako funkcionira!"
Ovdje dolazi najbolji dio: za full-stack aplikacije koje rade u stvarnom vremenu, tu su WebSockets. Ovaj dio je super uzbudljiv, pa se pridružimo Ernieju i Bertu i saznajmo kako WebSockets funkcioniraju, njihove procedure implementacije, zašto su važni i još mnogo toga.
Što su WebSockets? Početnički slom
WebSockets su slični neprekidnom telefonskom pozivu između klijenta (vašeg web preglednika) i poslužitelja. Razlikuju se od HTTP protokola koji funkcionira na način "pošalji pismo, čekaj odgovor". Uz WebSockets, obje strane mogu slobodno razgovarati kako žele. Značajke WebSockets uključuju sljedeće:
- Full-duplex: Moguće je da i klijent i poslužitelj prenose podatke istovremeno.
- Niska latencija: nema pretjerano ponovljenih rukovanja; podaci mogu slobodno teći.
- Lagan: poruke su male što smanjuje korištenje propusnosti.
Primjer: zamislite sportski semafor koji se stalno ažurira. S HTTP-om, klijent stalno mora poslati neželjenu poruku poslužitelju svake sekunde, "Ima li promjena rezultata?" Uz WebSockets, poslužitelj objavljuje, "GOAL!" istog trenutka kad se dogodi.
WebSockets nasuprot HTTP-u: Što je nova vrućina?
Bert sjedi i češka se po glavi. “Ali HTTP radi dobro za većinu aplikacija. Zašto pomicati vratnice?” Ernie se tiho nasmije, uzme marker i počne pisati nešto na ploču.
"Počnimo od vrha", kaže on. “Recimo, ažuriranja života u stvarnom vremenu, kao što su sportski rezultati uživo. Klijenti moraju pitati poslužitelja svake sekunde: 'Moram li nešto znati?' To je glasanje, tako da svakih trideset sekundi morate pitati: 'Sastajemo li se?' Smiješno, zar ne? Također koristi veliku propusnost.”
WebSockets ovo mijenja:
- Ažuriranja u stvarnom vremenu: podaci na poslužitelju šalju se u trenutku kada se promijene; nije potrebno anketiranje.
- Aplikacije za chat: nije potrebno osvježavanje stranice. Poruke naviru dok tipkate.
- Videoigre za više igrača: Nema više zastajkivanja. Radnje se neprimjetno prikazuju na zaslonima.
“HTTP je prilično pristojan u radu sa statičnim stvarima kao što su blog ili stranica proizvoda. Međutim, kada je riječ o interakcijama uživo, potrebna je trajna veza. WebSockets."
Stvaranje aplikacije za chat u stvarnom vremenu: dobre stvari počinju
Ernie čisti svoje naočale. "Dakle, napravimo jednostavnu aplikaciju za chat", uzvikuje Ernie. "Imat ćemo Node.js poslužitelj za pozadinu i React aplikaciju za sučelje. Spremni?"
1. Napravite Socket.IO Backend
"Uzmite Node.js poslužitelj jer će vam trebati za dio Socket.IO", kaže Ernie dok stvarno brzo tipka:
npm init -y npm install express socket.io
Kod poslužitelja (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'); });
“Klijent i poslužitelj mogu međusobno komunicirati zahvaljujući Socket.IO-ovom rukovanju WebSocket vezama. Kada klijent pozove funkciju (sendMessage), poslužitelj šalje poruku svima koji su povezani putem (io.emit). Prilično jednostavno, zar ne?”
2. Sučelje s Reactom
“Sada je moj red. Krenimo raditi na React klijentu,” kaže Bert.
npx create-react-app chat-client cd chat-client npm install socket.io-client
Komponenta chata (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;
Kako radi:
- Poslužitelj šalje poruke putem WebSocketa svim klijentima koji su povezani.
- Aplikacija React jednostranička je aplikacija koja može osvježiti korisničko sučelje bez ponovnog učitavanja stranice.
Testiraj:
- Za pokretanje poslužitelja unesite čvor server.js u konzolu.
- Za pokretanje React aplikacije unesite npm start u konzolu.
- S dvije otvorene kartice u pregledniku, upišite poruku u jednu karticu i primijetite kako će gotovo trenutno druga kartica prikazati istu poruku.
Primjeri korištenja u stvarnom životu
To je ono što je Bert namjeravao izgraditi na temelju aplikacije, ali Ernie spominje: "Većina aplikacija iz stvarnog života treba malo rukovanja pogreškama i način da se proširi okvir za razvoj." Pogledajmo neke moguće probleme.
1. Linija spajanja zaustavlja
Implementirajte strategiju ponovnog povezivanja u React klijentu.
socket.on('disconnect', () => { console.log('Disconnected. Trying to reconnect...'); socket.connect(); // Auto-reconnect });
2. Identitet korisnika
Osigurajte WebSocket pomoću autentificiranih JWT tokena.
// 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(); } });
3. Skaliranje pomoću Redisa
Uvedite prijenos poruka između različitih poslužitelja pomoću Redisa.
npm install redis
Šifra poslužitelja:
const redis = require('redis'); const subscriber = redis.createClient(); subscriber.subscribe('chat-channel'); subscriber.on('message', (channel, message) => { io.emit('receiveMessage', message); });
Izvan chata: Uređivanje zajedničkog dokumenta
Ovo je Bertova sljedeća ideja - uređivač sličan Google dokumentima. Ernie kaže: "Možete koristiti web utičnice za slušanje promjena koje su napravili različiti ljudi i njihovo spajanje."
Na primjer:
Korisnik A upisuje: "Zdravo"
Korisnik B uklanja "o" i dodaje ", svijet"
Poslužitelj sluša svaki pritisak tipke i emitira ga svim klijentima, kako bi njihovi klijenti prikazali AŽURIRANI dokument.
Isječak koda:
// Client sends keystrokes textarea.addEventListener('input', (e) => { socket.emit('textChange', e.target.value); }); // Server broadcasts changes socket.on('textChange', (text) => { io.emit('updateText', text); });
Sigurnosna pitanja
Ernie nas upozorava da: "Nikad ne biste trebali koristiti WebSockets bez HTTPS/WSS!"
- Koristite WSS (WebSocket Secure):
const io = new Server(server, { cors: { origin: "https://yourdomain.com" }, });
Potvrdite sve unose kako biste očistili sve podatke koji bi mogli dovesti do XSS napada.
Implementirajte ograničenje stope za korisnike koji šalju neželjenu poštu.
FAQ
P: Je li brzina WebSockets mnogo bolja od HTTP-a?
O: Da! Za trenutne aplikacije, WebSockets su najbolji jer uklanjaju potrebu za provođenjem ankete.
P: Je li moguće koristiti REST API zajedno s WebSockets?
O: Da, definitivno! Koristite WebSockets s ažuriranjima uživo i REST za izvođenje CRUD operacija.
P: Kako se nositi s padom poslužitelja?
O: Klijenti se mogu automatski ponovno povezati (pogledajte gornju logiku ponovnog povezivanja).
Završne riječi
Bertova aplikacija za chat sada šarmirano pinga u stvarnom vremenu, a Ernie se zadovoljno smiješi. WebSockets nisu samo za chatove, već također služe u svrhu live nadzornih ploča, igranja, IoT-a i više.
Vaš red: samo naprijed i isprobajte primjere, uništite ih i stvorite nešto novo. Vaše aplikacije u stvarnom vremenu čekaju!