Μαζί, ο Bert και ο Ernie, δύο φίλοι εργάζονται στο δευτερεύον έργο των ονείρων τους: μια εφαρμογή συνομιλίας που επιτρέπει συνομιλίες σε πραγματικό χρόνο για ομάδες που εργάζονται εξ αποστάσεως. Ο προγραμματιστής front-end Bert δύσκολα μπορεί να συγκρατηθεί καθώς μοιράζεται λαμπερά νέα χαρακτηριστικά με τον ειδικό φίλο του στο backend. "Ματιά! Μπορώ να πληκτρολογήσω ένα μήνυμα και αποστέλλεται στον διακομιστή και μπορώ να δω μια απάντηση να εμφανίζεται σχεδόν αμέσως!» Ο Έρνι, ο γκουρού του backend, συνοφρυώνεται. «Μα πώς λύνεις το θέμα δύο ανθρώπων που προσπαθούν να συνομιλήσουν ταυτόχρονα; Η εφαρμογή σας συνεχίζει να ανανεώνει τη σελίδα αντί να σας επιτρέπει να «δείτε» τη συνομιλία, γεγονός που καθιστά αδύνατη τη συνομιλία σε πραγματικό χρόνο.»
Η πρόκληση είναι ότι η εφαρμογή του Bert λειτουργεί σε HTTP στο οποίο ένας πελάτης πρέπει να ζητήσει μια ανάκτηση από τον διακομιστή. Ο Ernie συνοψίζει: «Είναι σαν να σου στέλνουν μηνύματα όλοι οι φίλοι σου, αλλά ξαφνικά δεν μπορείς να δεις καμία από τις απαντήσεις μέχρι να κάνεις ανανέωση για να ελέγξεις αν υπάρχουν νέα μηνύματα επειδή δεν μπορούν να δουν το τελευταίο σου μήνυμα μέχρι να το ανανεώσεις και έτσι λειτουργεί το HTTP!»
Εδώ έρχεται το καλύτερο μέρος: για εφαρμογές πλήρους στοίβας που λειτουργούν σε πραγματικό χρόνο, υπάρχει το WebSockets. Αυτό το μέρος είναι εξαιρετικά συναρπαστικό, οπότε ας έρθουμε μαζί με τον Ernie και τον Bert και μάθουμε πώς λειτουργούν τα WebSockets, τις διαδικασίες εφαρμογής τους, το σκεπτικό πίσω από τη σημασία τους και πολλά άλλα.
Τα WebSockets είναι παρόμοια με μια συνεχή τηλεφωνική κλήση μεταξύ ενός πελάτη (το πρόγραμμα περιήγησης ιστού σας) και ενός διακομιστή. Διαφέρουν από το πρωτόκολλο HTTP που λειτουργεί με τον τρόπο, «στείλτε μια επιστολή, περιμένετε μια απάντηση». Με το WebSockets, και τα δύο μέρη μπορούν να συνομιλούν ελεύθερα όπως θέλουν. Τα χαρακτηριστικά του WebSockets περιλαμβάνουν τα ακόλουθα:
Παράδειγμα: Φανταστείτε έναν αθλητικό πίνακα αποτελεσμάτων που ενημερώνεται συνεχώς. Με το HTTP, ο πελάτης πρέπει συνεχώς να στέλνει ανεπιθύμητα μηνύματα στον διακομιστή κάθε δευτερόλεπτο, "Κάθε αλλαγή βαθμολογίας;" Με το WebSockets, ο διακομιστής ανακοινώνει, "GOAL!" τη στιγμή που θα συμβεί.
Ο Μπερτ κάθεται πίσω και ξύνει το κεφάλι του. «Αλλά το HTTP λειτουργεί καλά για τις περισσότερες εφαρμογές. Γιατί να μετακινήσετε τα γκολπόστ;» Ο Έρνι γελάει απαλά, παίρνει ένα μαρκαδόρο και αρχίζει να γράφει κάτι στον πίνακα.
«Ας ξεκινήσουμε από την κορυφή», λέει. «Ας πούμε ενημερώσεις ζωής σε πραγματικό χρόνο, όπως ζωντανά αποτελέσματα αθλητικών αγώνων. Οι πελάτες πρέπει να ρωτούν τον διακομιστή κάθε δευτερόλεπτο: "Υπάρχει κάτι που πρέπει να μάθω;" Αυτό είναι δημοσκόπηση, οπότε κάθε τριάντα δευτερόλεπτα, πρέπει να ρωτάτε, "Συναντιόμαστε;" Γελοίο, όχι; Χρησιμοποιεί επίσης πολύ εύρος ζώνης."
Τα WebSockets αλλάζουν αυτό:
«Το HTTP είναι αρκετά αξιοπρεπές στην αντιμετώπιση στατικών πραγμάτων, όπως ένα blog ή μια σελίδα προϊόντος. Ωστόσο, όταν πρόκειται για ζωντανές αλληλεπιδράσεις, απαιτείται μια επίμονη σύνδεση. WebSockets."
Ο Έρνι καθαρίζει τα γυαλιά του. "Λοιπόν, ας φτιάξουμε μια απλή εφαρμογή συνομιλίας", αναφωνεί ο Ernie. "Θα έχουμε έναν διακομιστή Node.js για το backend και μια εφαρμογή React για το frontend. Έτοιμοι;"
«Πιάστε έναν διακομιστή 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», λέει ο Bert.
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;
Πώς λειτουργεί:
Δοκιμάστε το:
Αυτό σκόπευε να δημιουργήσει ο Bert με βάση την εφαρμογή, αλλά ο Ernie αναφέρει: «Οι περισσότερες εφαρμογές της πραγματικής ζωής χρειάζονται λίγο χειρισμό λαθών και έναν τρόπο επέκτασης του πλαισίου ανάπτυξης». Ας δούμε μερικά πιθανά προβλήματα.
Εφαρμόστε μια στρατηγική επανασύνδεσης στον πελάτη 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: Επεξεργασία ενός κοινόχρηστου εγγράφου
Αυτή είναι η επόμενη ιδέα του Bert - ένα πρόγραμμα επεξεργασίας παρόμοιο με το Google Docs. Ο Ernie λέει, "Μπορείτε να χρησιμοποιήσετε τις υποδοχές Ιστού για να ακούσετε τις αλλαγές που γίνονται από διαφορετικά άτομα και να τις συγχωνεύσετε."
Για παράδειγμα:
Τύπος χρήστη Α: "Γεια"
Ο χρήστης Β αφαιρεί το "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); });
Ο Ernie μας προειδοποιεί ότι: "Δεν πρέπει ποτέ να χρησιμοποιείτε WebSockets χωρίς HTTPS/WSS!"
const io = new Server(server, { cors: { origin: "https://yourdomain.com" }, });
Επικυρώστε όλες τις εισόδους ώστε να απολυμανθούν τυχόν δεδομένα που θα μπορούσαν να οδηγήσουν σε επιθέσεις XSS.
Εφαρμογή ορίου ποσοστού σε χρήστες με συμπεριφορά ανεπιθύμητης αλληλογραφίας.
Ε: Είναι η ταχύτητα των WebSockets πολύ καλύτερη από αυτή του HTTP;
Α: Ναι! Για στιγμιαίες εφαρμογές, τα WebSockets είναι τα καλύτερα γιατί αφαιρούν την ανάγκη διεξαγωγής δημοσκοπήσεων.
Ε: Είναι δυνατή η χρήση των API REST μαζί με τα WebSockets;
Α: Ναι, σίγουρα! Χρησιμοποιήστε WebSockets με ζωντανές ενημερώσεις και REST για την εκτέλεση λειτουργιών CRUD.
Ε: Πώς μπορώ να αντιμετωπίσω ένα σφάλμα διακομιστή;
Α: Οι πελάτες μπορούν να επανασυνδεθούν αυτόματα (δείτε τη λογική επανασύνδεσης παραπάνω).
Η εφαρμογή συνομιλίας του Bert κάνει ping με γοητεία σε πραγματικό χρόνο και ο Έρνι χαμογελά με ικανοποίηση. Τα WebSockets δεν προορίζονται μόνο για συνομιλίες, αλλά εξυπηρετούν επίσης το σκοπό των ζωντανών πινάκων ελέγχου, των παιχνιδιών, του IoT και άλλων.
Η σειρά σας: Προχωρήστε και δοκιμάστε τα παραδείγματα, καταστρέψτε τα και δημιουργήστε κάτι νέο. Οι εφαρμογές σας σε πραγματικό χρόνο περιμένουν!