Dateiverarbeitung in Echtzeit mit Deno und WebSockets
Mit dem Aufkommen von Echtzeitanwendungen suchen Entwickler ständig nach effizienten Wegen, um Live-Datenströme zu handhaben und Dateien im laufenden Betrieb zu verarbeiten. Deno, eine moderne Laufzeitumgebung für JavaScript und TypeScript, bietet robuste WebSocket-Unterstützung und erweiterte Sicherheitsfunktionen, die es zu einer ausgezeichneten Wahl für den Aufbau sicherer Systeme zur Dateiverarbeitung in Echtzeit machen.
In diesem DevTip zeigen wir, wie Sie die WebSocket-Funktionen von Deno und sein sicheres Berechtigungsmodell nutzen, um einen Echtzeit-WebSocket-Server zu implementieren. Dieses Muster kann als Grundlage für Aufgaben der Dateiverarbeitung in Echtzeit dienen – etwa für das Überwachen und Verarbeiten von Dateidaten – als Teil eines umfassenderen Anwendungsökosystems.
Warum Deno?
Deno bietet eine sichere Laufzeitumgebung mit TypeScript-Unterstützung, einem integrierten Berechtigungssystem und einer Sandbox-Umgebung. Diese Funktionen tragen dazu bei, dass Vorgänge, einschließlich Aufgaben der Dateiverarbeitung, sicher ausgeführt werden, ohne unnötige Systemressourcen offenzulegen. Anders als Node.js konzentriert sich Deno auf Sicherheit und Einfachheit und gibt Ihnen mehr Kontrolle über den Zugriff auf Netzwerk und Dateisystem.
Einen WebSocket-Server einrichten
Erstellen Sie eine neue Datei mit dem Namen server.ts und fügen Sie den
folgenden Code hinzu:
Deno.serve((req) => {
if (req.headers.get('upgrade') !== 'websocket') {
return new Response(null, { status: 501 })
}
const { socket, response } = Deno.upgradeWebSocket(req)
socket.addEventListener('open', () => {
console.log('A client connected!')
})
socket.addEventListener('message', (event) => {
if (event.data === 'ping') {
// In a real application, you might trigger file processing here
socket.send('pong')
}
})
socket.addEventListener('error', (event) => {
console.error('WebSocket error:', event)
})
socket.addEventListener('close', () => {
console.log('A client disconnected')
})
return response
})
Den Server ausführen
Um den Server zu starten, führen Sie aus:
deno run --allow-net server.ts
Den WebSocket-Lebenszyklus verstehen
WebSocket-Verbindungen durchlaufen mehrere Zustände:
- CONNECTING (0): Der Anfangszustand während des Verbindungsaufbaus.
- OPEN (1): Die Verbindung ist aktiv und bereit für die Datenübertragung.
- CLOSING (2): Die Verbindung wird gerade geschlossen.
- CLOSED (3): Die Verbindung wurde beendet.
So können Sie beispielsweise prüfen, ob ein Socket bereit ist, bevor Sie eine Nachricht senden:
function isSocketReady(socket: WebSocket): boolean {
return socket.readyState === WebSocket.OPEN
}
socket.onmessage = (event) => {
if (!isSocketReady(socket)) {
return
}
// Handle message
}
Client-Implementierung
Nachfolgend finden Sie ein schlankes Client-Beispiel zum Testen des Servers:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<title>WebSocket Test</title>
</head>
<body>
<script>
const ws = new WebSocket('ws://localhost:8000')
ws.onopen = () => {
console.log('Connected to the server')
ws.send('ping')
}
ws.onmessage = (event) => {
console.log('Received:', event.data)
}
ws.onerror = (error) => {
console.error('WebSocket error:', error)
}
ws.onclose = () => {
console.log('Disconnected from the server')
}
</script>
</body>
</html>
Bewährte Verfahren für die Sicherheit
Wenn Sie Echtzeitanwendungen entwickeln, insbesondere solche mit Dateiverarbeitung, sollten Sie diese Sicherheitsmaßnahmen berücksichtigen:
1. Eingabevalidierung
Stellen Sie sicher, dass eingehende Daten korrekt formatiert sind, damit keine unerwarteten Eingaben
verarbeitet werden. Diese Sicherheits-Snippets veranschaulichen Prüfungen, die Sie in den
Nachrichten-Handler Ihres Servers integrieren; der oben gezeigte Ping/Pong-Server wendet sie nicht
automatisch an. Wenn sich eine Nachricht auf eine Datei bezieht, akzeptieren Sie eine autorisierte
Datei-ID, die einem servergesteuerten Pfad zugeordnet ist. Übergeben Sie niemals einen nicht
vertrauenswürdigen Dateinamen oder Pfad direkt an die Datei-APIs von Deno, und beschränken Sie jede
Berechtigung --allow-read oder --allow-write auf das
erforderliche Verzeichnis.
function validateMessage(data: unknown): boolean {
if (typeof data !== 'string') {
return false
}
try {
const message = JSON.parse(data)
return typeof message === 'object' && message !== null && !Array.isArray(message)
&& typeof message.type === 'string'
} catch {
return false
}
}
2. Ratenbegrenzung
Integrieren Sie einen Ratenbegrenzer, um akzeptierte Anwendungsnachrichten einzuschränken. Der
folgende beispielhafte In-Memory-Begrenzer arbeitet pro Prozess; lassen Sie in einem langlaufenden
Dienst inaktive Client-Einträge verfallen, begrenzen Sie die Gesamtzahl der Verbindungen und
verwenden Sie für clientId eine authentifizierte Identität oder eine vom
Server zugewiesene Verbindungs-ID.
class RateLimiter {
private requests = new Map<string, number[]>()
private readonly limit: number
private readonly window: number
constructor(limit = 100, window = 60000) {
this.limit = limit
this.window = window
}
isAllowed(clientId: string): boolean {
const now = Date.now()
const timestamps = this.requests.get(clientId) || []
const recent = timestamps.filter((time) => now - time < this.window)
if (recent.length >= this.limit) {
return false
}
recent.push(now)
this.requests.set(clientId, recent)
return true
}
}
3. Grenzen für Nachrichtengrößen
Prüfen Sie die UTF-8-Bytelänge akzeptierter Textnachrichten. Die Länge eines JavaScript-Strings zählt UTF-16-Codeeinheiten und ist daher keine Byteanzahl. Diese Prüfung läuft, nachdem WebSocket die Nachricht gepuffert und zugestellt hat, und das Codieren des Strings belegt einen weiteren Puffer. Sie begrenzt die nachfolgende Arbeit der Anwendung, nicht die Netzwerkpufferung oder den Spitzenspeicherbedarf. Der WebSocket-API fehlt Backpressure; verwenden Sie einen Server oder ein Gateway mit expliziten WebSocket-Nachrichtengrenzen, Verbindungsgrenzen und Ratenbegrenzungen, um nicht vertrauenswürdigen Datenverkehr vor der Verarbeitung durch die Anwendung zu begrenzen.
Platzieren Sie diesen Handler innerhalb von Deno.serve, wo sich das
hochgestufte socket im Gültigkeitsbereich befindet:
const MAX_MESSAGE_SIZE = 1024 * 1024 // 1 MiB of UTF-8 text
const encoder = new TextEncoder()
socket.addEventListener('message', (event) => {
if (typeof event.data !== 'string') {
socket.close(1003, 'Only text messages are accepted')
return
}
if (encoder.encode(event.data).byteLength > MAX_MESSAGE_SIZE) {
socket.close(1009, 'Message size exceeds limit')
return
}
// Process message
})
Fazit
Die integrierte WebSocket-Unterstützung und das starke Sicherheitsmodell von Deno machen es zu einem leistungsstarken Werkzeug für die Entwicklung von Echtzeitanwendungen, einschließlich solcher, die Dateien dynamisch verarbeiten. Wenn Sie die in diesem Leitfaden beschriebenen bewährten Verfahren anwenden, können Sie sichere und effiziente Systeme aufbauen, die Echtzeitdaten und Dateioperationen verarbeiten können.
Bei Transloadit kennen wir den Wert sicherer Kommunikation in Echtzeit. Entdecken Sie unseren Dienst File Filtering, um zu sehen, wie fortgeschrittene Dateiverarbeitung Ihre Echtzeitanwendungen ergänzen kann.
