Inleiding: Wanneer HTTP niet voldoende is
Samen werken Bert en Ernie, twee vrienden, aan het zijproject van hun dromen: een chat-app die realtimegesprekken mogelijk maakt voor teams die op afstand werken. De front-end coder Bert kan zichzelf nauwelijks inhouden terwijl hij glimmende nieuwe functies deelt met zijn backend-specialistvriend. "Kijk! Ik kan een bericht typen, het wordt naar de server gestuurd en ik zie bijna onmiddellijk een reactie verschijnen!" Ernie, de backend-goeroe, fronst. "Maar hoe los je het probleem op dat twee mensen tegelijkertijd een gesprek proberen te voeren? Je app blijft de pagina vernieuwen in plaats van je het gesprek te laten 'zien', waardoor het onmogelijk is om in realtime te chatten."
De uitdaging is dat Berts app op HTTP werkt, waarbij een client een fetch van de server moet aanvragen. Ernie vat samen: "Het is alsof al je vrienden je terug sms'en, maar dan zie je ineens geen van de antwoorden meer totdat je ververst om te controleren of er nieuwe berichten zijn, omdat ze je laatste bericht niet kunnen zien totdat je het ververst en zo werkt HTTP!"
Hier komt het beste deel: voor full-stack apps die in real-time werken, zijn er WebSockets. Dit deel is super spannend, dus laten we samen met Ernie en Bert ontdekken hoe WebSockets werken, hun implementatieprocedures, de reden achter hun belang en nog veel meer.
Wat zijn WebSockets? Een beginnersuitleg
WebSockets lijken op een doorlopend telefoongesprek tussen een client (uw webbrowser) en een server. Ze verschillen van het HTTP-protocol dat op dezelfde manier werkt als "stuur een brief, wacht op een antwoord". Met WebSockets kunnen beide partijen vrij met elkaar praten zoals ze willen. De functies van WebSockets omvatten het volgende:
- Full-duplex: Het is mogelijk dat zowel de client als de server gelijktijdig gegevens verzenden.
- Lage latentie: Er zijn geen overmatige herhaalde handshakes; gegevens kunnen vrij stromen.
- Lichtgewicht: Berichten zijn klein, waardoor er minder bandbreedte wordt gebruikt.
Voorbeeld: Stel je een constant bijgewerkt sport scorebord voor. Met HTTP moet de client de server elke seconde spammen met: "Is er een scorewijziging?" Met WebSockets kondigt de server aan: "GOAL!" op het moment dat het gebeurt.
WebSockets versus HTTP: wat is er nieuw?
Bert leunt achterover en krabt op zijn hoofd. "Maar HTTP werkt prima voor de meeste apps. Waarom de doelpalen verplaatsen?" Ernie lacht zachtjes, pakt een stift en begint iets op het whiteboard te schrijven.
“Laten we bij het begin beginnen,” zegt hij. “Laten we zeggen real-time life updates, zoals live sportuitslagen. Klanten moeten de server elke seconde vragen: 'Is er iets dat ik moet weten?' Dat is polling, dus elke dertig seconden moet je vragen: 'Zijn we aan het vergaderen?' Belachelijk, toch? Het gebruikt ook veel bandbreedte.”
WebSockets veranderen dit:
- Realtime-updates: Gegevens worden naar de server verzonden zodra ze veranderen. Er is geen polling nodig.
- Chattoepassingen: Geen paginaverversing vereist. Berichten stromen binnen terwijl u typt.
- Multiplayer videogames: Geen haperende bewegingen meer. Acties worden naadloos op schermen weergegeven.
“HTTP is redelijk goed in het omgaan met statische zaken zoals een blog of productpagina. Als het echter gaat om live interacties, is een permanente verbinding vereist. WebSockets.”
Een realtime chat-app maken: het goede begint
Ernie poetst zijn bril. "Dus, laten we een simpele chatapplicatie maken," roept Ernie uit. "We krijgen een Node.js-server voor de backend en een React-app voor de frontend. Klaar?"
1. Maak een Socket.IO-backend
"Pak een Node.js-server, want je hebt hem nodig voor het Socket.IO-gedeelte", zegt Ernie terwijl hij heel snel typt:
npm init -y npm install express socket.io
Servercode (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'); });
"De client en server kunnen met elkaar communiceren dankzij Socket.IO's afhandeling van WebSocket-verbindingen. Wanneer de client de (sendMessage)-functie aanroept, stuurt de server het bericht naar iedereen die via (io.emit) is verbonden. Vrij eenvoudig, toch?"
2. Frontend met React
"Nu is het mijn beurt. Laten we aan de slag gaan met de React-client," zegt Bert.
npx create-react-app chat-client cd chat-client npm install socket.io-client
Chatcomponent (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;
Hoe het werkt:
- Berichten worden door de server via een WebSocket verzonden naar alle verbonden clients.
- De React-applicatie is een single-page-applicatie die de gebruikersinterface kan vernieuwen zonder de pagina opnieuw te laden.
Test het:
- Om de server te starten, voert u node server.js in de console in.
- Om de React-applicatie te starten, voert u npm start in de console in.
- Als u twee tabbladen in uw browser open hebt staan, typt u een bericht in het ene tabblad. U zult zien dat vrijwel direct hetzelfde bericht op het andere tabblad wordt weergegeven.
Voorbeelden van toepassingen in het echte leven
Dit is wat Bert van plan was te bouwen op basis van de applicatie, maar Ernie geeft aan: "De meeste echte applicaties hebben een beetje foutverwerking nodig en een manier om het raamwerk voor ontwikkeling uit te breiden." Laten we eens kijken naar enkele waarschijnlijke problemen.
1. Verbindingslijn stopt
Implementeer een herverbindingsstrategie in de React-client.
socket.on('disconnect', () => { console.log('Disconnected. Trying to reconnect...'); socket.connect(); // Auto-reconnect });
2. Gebruikersidentiteit
Beveiligde WebSocket met behulp van geverifieerde JWT-tokens.
// 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. Schalen met Redis
Introduceer berichtenuitwisseling tussen verschillende servers met behulp van Redis.
npm install redis
Servercode:
const redis = require('redis'); const subscriber = redis.createClient(); subscriber.subscribe('chat-channel'); subscriber.on('message', (channel, message) => { io.emit('receiveMessage', message); });
Beyond Chat: een gedeeld document bewerken
Dit is Berts volgende idee: een editor die lijkt op Google Docs. Ernie zegt: "Je kunt websockets gebruiken om te luisteren naar wijzigingen die door verschillende mensen zijn aangebracht en deze samen te voegen."
Bijvoorbeeld :
Gebruiker A typt: “Hallo”
Gebruiker B verwijdert “o” en voegt “, World” toe
De server luistert naar elke toetsaanslag en stuurt deze door naar alle clients, zodat hun respectievelijke clients een BIJGEWERKT document kunnen genereren.
Codefragment:
// Client sends keystrokes textarea.addEventListener('input', (e) => { socket.emit('textChange', e.target.value); }); // Server broadcasts changes socket.on('textChange', (text) => { io.emit('updateText', text); });
Veiligheidsproblemen
Ernie waarschuwt ons: “Je mag nooit WebSockets gebruiken zonder HTTPS/WSS!”
- Gebruik WSS (WebSocket Secure):
const io = new Server(server, { cors: { origin: "https://yourdomain.com" }, });
Valideer alle invoer om alle gegevens te verwijderen die tot XSS-aanvallen kunnen leiden.
Stel een limiet in voor gebruikers die spam versturen.
Veelgestelde vragen
V: Is de snelheid van WebSockets veel beter dan die van HTTP?
A: Ja! Voor directe toepassingen zijn WebSockets het beste, omdat ze de noodzaak om polling uit te voeren wegnemen.
V: Is het mogelijk om REST API's te gebruiken in combinatie met WebSockets?
A: Jazeker! Gebruik WebSockets met live updates en REST voor het uitvoeren van CRUD-bewerkingen.
V: Hoe ga ik om met een server die crasht?
A: Clients kunnen automatisch opnieuw verbinding maken (zie bovenstaande logica voor opnieuw verbinden).
Laatste woorden
Berts chat-app pingt nu met realtime charme en Ernie glimlacht tevreden. WebSockets zijn niet alleen voor chats, maar dienen ook als live dashboards, gaming, IoT en meer.
Jouw beurt: Ga je gang en probeer de voorbeelden uit, vernietig ze en creëer iets nieuws. Jouw real-time apps wachten!