
Teilen Sie:
Kelly J. Andrews ist eine Entwicklerin, die sich für Nexmo einsetzt. Sie bastelt seit über 30 Jahren an Computern und verwendete BASIC zum ersten Mal im Alter von 5 Jahren.
Erst als er 1997 seine erste Webseite erstellte und JavaScript zum ersten Mal ausprobierte, fand er seine wahre Berufung. Kelly kämpft jetzt für JavaScript, testbaren Code und schnelle Lieferung.
Er singt Karaoke, zaubert oder feuert die Cubs und die Fighting Irish an.
SMS-Demo in Echtzeit mit React, Node und Google Translate
Lesedauer: 8 Minuten
Letztes Jahr habe ich mit der Google Translate API gearbeitet, um SMS-Nachrichten zu übersetzen. Nachdem ich es dem Rest des Teams gezeigt hatte, wollten sie eine Demo, die sie anderen Entwicklern auf Konferenzen, an denen wir teilnahmen, vorführen konnten. Daraufhin habe ich ein Frontend mit React erstellt, das die Übersetzungen in Echtzeit anzeigen konnte.
Aufbau des WebSocket
Was ist ein WebSocket?
Für diese Demo habe ich beschlossen, dass die Verwendung eines WebSockets eine gute Lösung wäre. Wenn Sie WebSockets noch nicht kennen, handelt es sich um ein Protokoll, mit dem ein Client und ein Server in Echtzeit kommunizieren können. WebSockets sind bidirektional, d. h. der Client und der Server können sowohl Nachrichten senden als auch empfangen. Wenn Sie zum ersten Mal eine Verbindung zu einem WebSocket herstellen, wird die Verbindung durch ein Upgrade eines HTTP-Protokolls auf das WebSocket-Protokoll hergestellt und so lange aufrechterhalten, wie sie ununterbrochen läuft. Sobald die Verbindung hergestellt ist, wird ein kontinuierlicher Strom von Inhalten bereitgestellt. Das ist genau das, was wir brauchen, um eingehende, übersetzte SMS-Nachrichten zu empfangen.
Erstellen Sie den WebSocket-Server in Node
Als ersten Schritt zur Erstellung der WebSockets benötigt der Server einen Pfad, um Client-Verbindungen zu ermöglichen. Ausgehend von der ursprünglichen Serverdatei aus meinem vorherigen Beitragkönnen wir ein paar kleine Änderungen vornehmen, um den WebSocket-Server und die vom Client benötigten Ereignisse und Listener zu erstellen.
Mit Hilfe des ws Pakets von NPM können wir schnell das erstellen, was wir brauchen, damit es funktioniert.
Nach der Installation binden Sie das Paket in Ihre Serverdatei ein und erstellen den WebSocket-Server. WS erlaubt eine path Option, um die Route festzulegen, die der Client für die Verbindung verwendet.
const express = require('express');
const WebSocket = require('ws');
const app = express();
const server = http.createServer(app);
const wss = new WebSocket.Server({ server, path: "/socket" });Mit diesem Teil des Codes hat der Client nun einen Ort, an dem er sich mit der WebSocket-Route verbinden kann /socket. Da der Server nun einsatzbereit ist, müssen Sie nun auf ein connection Ereignis. Wenn der Client eine Verbindung herstellt, verwendet der Server den folgenden Code, um die anderen benötigten Listener einzurichten:
wss.on('connection', (ws) => {
ws.isAlive = true;
ws.translateTo = 'en';
ws.on('pong', () => {
ws.isAlive = true;
});
ws.on('message', (message) => {
translateTo = message;
});
});
Es gibt zwei wichtige Punkte, die hervorzuheben sind:
Bei der Verbindung setzen wir die Eigenschaft
isAliveauftrueund warten auf daspongEreignis. Dieses Ereignis dient dem Server zur Überprüfung und Aufrechterhaltung der Verbindung mit dem Client. Der Server sendet einpingund antwortet mitpongum zu verifizieren, dass die Verbindung noch besteht.Hier richte ich
translateToals eine zu speichernde Eigenschaft.translateTowird durch jeden Client mit einem Dropdown eingestellt. Wenn jemand mit unserer Stand-Demo-App eine andere Sprache auswählt, setzt diese Aktion dies, um die SMS-Texte in die gewünschte Sprache zu übersetzen.
Die Verbindung lebendig halten
Ein wichtiger Punkt ist die Überprüfung von Clients, die die Verbindung unterbrechen. Es ist möglich, dass der Server die Trennung der Verbindung nicht bemerkt und dass Probleme auftreten. Mit einem guten Freund setInterval()können wir überprüfen, ob unsere Kunden noch da sind, und sie bei Bedarf wieder verbinden.
setInterval(() => {
wss.clients.forEach((ws) => {
if (!ws.isAlive) return ws.terminate();
ws.isAlive = false;
ws.ping(null, false, true);
});
}, 10000);
Senden von Nachrichten an den Client
Nun, da der WebSocket verbunden ist und überwacht wird, können wir die eingehenden Nachrichten von Nexmo, die Übersetzung und die Antwort an den Client verarbeiten. Die Methode handleRoute muss von ihrem ursprünglichen Zustand aus aktualisiert werden, um die Antwort für jeden Client hinzuzufügen.
const handleRoute = (req, res) => {
let params = req.body;
if (req.method === "GET") {
params = req.query
}
if (!params.to || !params.msisdn) {
res.status(400).send({ 'error': 'This is not a valid inbound SMS message!' });
} else {
wss.clients.forEach(async (client) => {
let translation = await translateText(params, client.translateTo);
let response = {
from: obfuscateNumber(req.body.msisdn),
translation: translation.translatedText,
originalLanguage: translation.detectedSourceLanguage,
originalMessage: params.text,
translatedTo: client.translateTo
}
client.send(JSON.stringify(response));
});
res.status(200).end();
}
};
Die Methode wss.clients.forEach Methode iteriert durch jede Verbindung und sendet die SMS-Parameter von Nexmo an die Google Translate API. Sobald die Übersetzung zurückkommt, können wir entscheiden, welche Daten das Frontend haben soll, und sie als String zurückgeben, wie ich es hier getan habe mit client.send(JSON.stringify(response)).
Um zu rekapitulieren, was hier passiert ist: Jeder Client verbindet sich mit dem WebSocket-Server, indem er die /socket Route aufruft und eine Verbindung herstellt. Eine SMS-Nachricht geht vom Telefon des Absenders an Nexmo, das dann die /inboundSMS Route aufruft. Die App leitet die Textnachricht an die Google Translate API für jeden verbundenen Client weiter und sendet sie schließlich zurück an die Client-Benutzeroberfläche.
Diagram of WebSocket Flow
Als Nächstes erstellen wir die UI-Teile, um sie auf dem Bildschirm anzuzeigen.
WebSockets mit React
Wenn der WebSocket-Server läuft, können wir mit der Anzeige der Nachrichten auf dem Bildschirm fortfahren. Da ich gerne mit Reactund, was noch wichtiger ist, React Hooksverwende, machte ich mich auf die Suche nach etwas, das bei der Verbindung mit WebSockets hilft. Und tatsächlich, ich fand etwas, das genau meinen Bedürfnissen entsprach.
Die Benutzeroberfläche der Demo-Anwendung wurde mit create-react-apperstellt, und ich habe das Grommet Framework. Diese Themen würden den Rahmen dieses Beitrags sprengen, aber Sie können sich meinen Quellcode und mitverfolgen.
Verbinden mit dem WebSocket
Der erste Schritt besteht darin, eine Verbindung herzustellen und eine wechselseitige Kommunikation zu beginnen. Das Modul, das ich gefunden habe, ist react-use-websocketund es machte die Einrichtung super einfach.
Es gibt tonnenweise dieser React-Hook-Bibliotheken, mit denen man in kurzer Zeit beeindruckende Funktionen erstellen kann. In diesem Fall genügte es, das Modul zu importieren und ein paar Elemente für die Konfiguration einzurichten, um eine Verbindung herzustellen.
import useWebSocket from 'react-use-websocket';
const App = () => {
const STATIC_OPTIONS = useMemo(() => ({
shouldReconnect: (closeEvent) => true,
}), []);
const protocolPrefix = window.location.protocol === 'https:' ? 'wss:' : 'ws:';
let { host } = window.location;
const [sendMessage, lastMessage, readyState] = useWebSocket(`${protocolPrefix}//${host}/socket`, STATIC_OPTIONS);
//...
}
In der Komponente importieren wir die useWebSocket Methode zur Übergabe der WebSocket-URL und des Objekts STATIC_OPTIONS als zweites Argument. Die Methode useWebSocket Methode ist ein benutzerdefinierter Hook, der die sendMessage Methode, lastMessage Objekt vom Server zurückgibt (das sind unsere übersetzten Nachrichten), und die readyState die eine ganze Zahl ist, die uns den Status der Verbindung angibt.
Empfangen eingehender Nachrichten
Sobald react-use-websocket die Verbindung zum Server hergestellt hat, können wir nun beginnen, auf Nachrichten von der lastMessage Eigenschaft. Wenn wir eingehende Nachrichten vom Server erhalten, werden diese hier eingetragen und die Komponente aktualisiert. Wenn Ihr Server mehrere Nachrichtentypen hat, können Sie diese Informationen hier erkennen. Da wir nur einen haben, ist dies eine einfachere Implementierung.
const [messageHistory, setMessageHistory] = useState([]);
useEffect(() => {
if (lastMessage !== null) {
setMessageHistory(prev => prev.concat(lastMessage))
}
}, [lastMessage]);
return (
<Main>
{messageHistory.map((message, idx) => {
let msg = JSON.parse(message.data);
return (
<Box>
<Text>From: {msg.from}</Text>
<Heading level={2}>{msg.translation}</Heading>
</Box>
)
})}
</Main>
)
Der eingebaute Haken useEffect wird jedes Mal ausgeführt, wenn der Status aktualisiert wird. Wenn lastMessage nicht null ist, fügt er die neue Nachricht an das Ende des vorherigen Nachrichtenzustands-Arrays an, und die Benutzeroberfläche wird mit der map Funktion, um alle Nachrichten darzustellen. Es ist in der messageHistory werden alle JSON-Strings, die wir vom Server übergeben haben, gespeichert. Die Hauptfunktionalität unserer WebSocket ist vollständig, aber ich möchte noch ein paar weitere Elemente hinzufügen.
Senden von Nachrichten an den Server
Da es sich um eine Übersetzungsdemo handelt, ist die Verwendung von mehr als einer Sprache eine hervorragende Möglichkeit, die Leistungsfähigkeit der Google Translate API in Verbindung mit Nexmo SMS-Nachrichten zu zeigen. Ich habe ein Dropdown-Menü mit Sprachen zur Auswahl erstellt. Dieses Dropdown ist der Ort, an dem die bidirektionale Kommunikation mit dem Server stattfindet, und die App sendet die ausgewählte Sprache vom Client.
const languages = [
{ label: "English", value: "en"},
{ label: "French", value: "fr"},
{ label: "German", value: "de"},
{ label: "Spanish", value: "es"}
];
<Select
labelKey="label"
onChange={({ option }) => {
sendMessage(option.value)
setTranslateValue(option.label)
}}
options={languages}
value={translateValue}
valueKey="value"
/>Hier wird die sendMessage Funktion von react-use-websocket ist die Funktion, mit der wir Informationen an unseren Server zurücksenden und verbrauchen können. Bei diesem Prozess kommt uns der Event-Handler, den wir zuvor eingerichtet haben, sehr gelegen. Dieses Dropdown bestimmt, in welche Sprache die Google Translate API die Nachricht übersetzt und auf dem Bildschirm anzeigt.
Anzeige des Verbindungsstatus
Da es sich um eine Demo in einer Konferenzumgebung handelt, dachte ich, dass eine Konnektivitätsanzeige eine gute Idee wäre. Solange das Front-End mit dem WebSocket verbunden ist, leuchtet die Anzeige grün.
const CONNECTION_STATUS_CONNECTING = 0;
const CONNECTION_STATUS_OPEN = 1;
const CONNECTION_STATUS_CLOSING = 2;
function Status({ status }) {
switch (status) {
case CONNECTION_STATUS_OPEN:
return <>Connected<div className="led green"></div></>;
case CONNECTION_STATUS_CONNECTING:
return <>Connecting<div className="led yellow"></div></>;
case CONNECTION_STATUS_CLOSING:
return <>Closing<div className="led yellow"></div></>;
default:
return <>Disconnected<div className="led grey"></div></>;;
}
}
//....
<Status status={readyState} />
//...Die Komponente Status Komponente verwendet die Taste readyState um zwischen den verschiedenen Zuständen zu wechseln und zeigt dies dem Benutzer an. Wenn sie rot wird, wissen Sie, dass etwas mit dem WebSocket-Server nicht in Ordnung ist, und Sie sollten das Problem überprüfen.
Wenn alles eingerichtet ist, sieht es in etwa so aus:
Animation of Working Demo App
Probieren Sie es aus
Der Code der Demo-Anwendung befindet sich auf unserer Community-GitHub-Organisation, und Sie können ihn auch selbst ausprobieren. Ich habe eine README-Datei erstellt, die Ihnen bei der Einrichtung helfen soll, damit Sie die Anwendung lokal auf Ihrem Server ausführen oder sie auf Heroku bereitstellen können. Ich habe auch ein Dockerfile zur Verfügung gestellt, falls Sie diesen Weg bevorzugen. Lassen Sie mich wissen, was Sie davon halten, und wenn Sie irgendwelche Probleme haben, zögern Sie nicht, sich zu melden und ein Problem im Repo einzureichen.
Teilen Sie:
Kelly J. Andrews ist eine Entwicklerin, die sich für Nexmo einsetzt. Sie bastelt seit über 30 Jahren an Computern und verwendete BASIC zum ersten Mal im Alter von 5 Jahren.
Erst als er 1997 seine erste Webseite erstellte und JavaScript zum ersten Mal ausprobierte, fand er seine wahre Berufung. Kelly kämpft jetzt für JavaScript, testbaren Code und schnelle Lieferung.
Er singt Karaoke, zaubert oder feuert die Cubs und die Fighting Irish an.