Ontwikkel een WebSocket API Gateway voor Geavanceerde Verbindingsbeheer
description
Met deze prompt kan de gebruiker een geavanceerde WebSocket API Gateway ontwerpen en implementeren die complexe verbindingsscenario’s ondersteunt, zoals authenticatie, throttling en routing. Dit lost problemen op rond schaalbaarheid en beveiliging die standaard WebSocket-implementaties niet afdekken. Het is beter dan alternatieven omdat het een totaaloplossing biedt voor beheer en optimalisatie van WebSocket-verbindingen in professionele omgevingen.
prompt
Help me bij het ontwikkelen van een WebSocket API Gateway die geavanceerd verbindingsbeheer mogelijk maakt. Mijn servertechnologie: <voer de servertechnologie in die ik gebruik> Mijn clienttechnologie: <voer de clienttechnologie in die ik gebruik> Welke functionaliteiten wil ik in de gateway integreren (bijv. authenticatie, throttling, routing): <beschrijf de gewenst ...
try_prompt
generate_helper
disclaimerOnPageApi
tags
ai_answers
provider: openai
model: gpt-4.1-nano
Natuurlijk! Hier zijn concrete architectuurtips, ontwerpprincipes en voorbeeldcode om een robuuste, schaalbare en veilige WebSocket API Gateway te bouwen op basis van jouw specificaties:
**Architectuurtips en ontwerpprincipes:**
1. **Gebruik een dedicated WebSocket server**: Hoewel je Node.js en Express gebruikt, overweeg een aparte WebSocket-server (bijvoorbeeld met `ws` of `socket.io`) naast je REST API voor betere schaalbaarheid en onderhoud.
2. **Authenticatie via JWT**:
- Verifieer JWT tokens bij het initialiseren van de WebSocket-verbinding.
- Verstrek een token tijdens de handshake of via een init-message.
3. **Throttling en rate limiting**:
- Implementeer rate limiting per client IP of token met Redis om schaalbaarheid te garanderen.
- Gebruik bijvoorbeeld `redis` en `bottleneck` of `express-rate-limit`-achtige oplossingen.
4. **Routing en boodschapbeheer**:
- Route berichten op basis van message types of kanalen.
- Overweeg een pub/sub-model met Redis voor schaalbare broadcast.
5. **State management met Redis**:
- Houd verbindingstoestanden, subscriptions en gebruikersgegevens bij in Redis.
- Gebruik Redis pub/sub voor communicatie tussen verschillende serverinstanties.
6. **Schaalbaarheid**:
- Plaats je WebSocket server achter een load balancer die sticky sessions ondersteunt (bijvoorbeeld via cookies of session ID).
- Gebruik Redis als centrale state store en messaging broker.
7. **Veiligheid**:
- Gebruik WSS (secure WebSocket) met SSL/TLS.
- Controleer JWT tokens en verval data correct.
---
**Voorbeeldimplementatie**
Hier is een basisvoorbeeld met `ws` voor WebSocket, `jsonwebtoken` voor JWT, en `redis` voor state management en rate limiting:
```javascript
const WebSocket = require('ws');
const jwt = require('jsonwebtoken');
const redis = require('redis');
const redisClient = redis.createClient();
const wss = new WebSocket.Server({ port: 8080 });
// Secret voor JWT verificatie
const JWT_SECRET = 'jouw_geheime_token';
wss.on('connection', async (ws, req) => {
const token = getTokenFromReq(req); // Haal token uit query params of headers
// Authenticatie
try {
const payload = jwt.verify(token, JWT_SECRET);
ws.userId = payload.sub;
// Initialize rate limiting
const ip = req.socket.remoteAddress;
const rateLimitKey = `rate_limit:${ip}`;
redisClient.get(rateLimitKey, (err, reply) => {
if (err) console.error(err);
const count = reply ? parseInt(reply) : 0;
if (count >= 100) { // Limiet, bijv. 100 messages per minuut
ws.send(JSON.stringify({ error: 'Rate limit exceeded' }));
ws.close();
return;
} else {
// Verhoog de counter
redisClient.multi()
.incr(rateLimitKey)
.expire(rateLimitKey, 60) // 60 seconden
.exec();
}
});
ws.on('message', (message) => {
// Routing of messages
handleMessage(ws, message);
});
ws.on('close', () => {
console.log(`Client ${ws.userId} disconnected`);
});
} catch (err) {
ws.send(JSON.stringify({ error: 'Authenticatie mislukt' }));
ws.close();
}
});
function getTokenFromReq(req) {
// Haal token uit query parameter of headers
const urlParams = new URL(req.url, 'http://localhost');
return urlParams.searchParams.get('token') || req.headers['sec-websocket-protocol'];
}
function handleMessage(ws, message) {
// Als je een bericht-structuur hebt, bijvoorbeeld JSON met type
try {
const data = JSON.parse(message);
switch (data.type) {
case 'subscribe':
// Voeg gebruiker toe aan channel in Redis
redisClient.sadd(`channels:${data.channel}`, ws.userId);
break;
case 'publish':
// Publiceer bericht naar channel
redisClient.smembers(`channels:${data.channel}`, (err, members) => {
if (err) console.error(err);
members.forEach(userId => {
// Stuur bericht naar alle clients die op dat kanaal zitten
// Dit vereist een manier om clients te matchen met userId
// Bijvoorbeeld door een Map van userId naar ws te houden
});
});
break;
default:
ws.send(JSON.stringify({ error: 'Onbekend type' }));
}
} catch (err) {
ws.send(JSON.stringify({ error: 'Ongeldig berichtformaat' }));
}
}
```
**Aanvullende tips:**
- Gebruik `helmet` en andere beveiligingsmaatregelen.
- Overweeg `socket.io` voor eenvoudiger events en fallback-opties.
- Implementeer monitoring en logging voor schaalbaarheid.
---
Wil je dat ik je help met een meer uitgebreide codebase of integraties?
provider: deepseek
model: deepseek-chat
Zeker! Hier een concrete architectuurhandleiding voor je WebSocket API Gateway in Node.js/Express voor React Native clients.
## Architectuur Overzicht
```
React Native Client ↔ WebSocket API Gateway (Node.js/Express) ↔ REST API Backend
↔
Redis (State/Sessions)
```
## Kern Componenten & Ontwerpprincipes
### 1. Express Server Setup met WebSocket Ondersteuning
```javascript
// server.js
const express = require('express');
const http = require('http');
const WebSocket = require('ws');
const redis = require('redis');
const app = express();
const server = http.createServer(app);
const wss = new WebSocket.Server({
server,
clientTracking: true,
perMessageDeflate: false // Betere controle bij throttling
});
// Redis clients
const redisClient = redis.createClient({
host: 'localhost',
port: 6379
});
const pubClient = redis.createClient();
const subClient = redis.createClient();
```
### 2. Geavanceerde JWT Authenticatie
```javascript
// middleware/auth.js
const jwt = require('jsonwebtoken');
const redisClient = require('./redis');
class WebSocketAuth {
static async authenticate(token) {
try {
// Check Redis blacklist eerst
const isBlacklisted = await redisClient.get(`blacklist:${token}`);
if (isBlacklisted) throw new Error('Token revoked');
const decoded = jwt.verify(token, process.env.JWT_SECRET);
// Valideer extra claims
if (!decoded.ws_access) throw new Error('No WebSocket access');
return decoded;
} catch (error) {
throw new Error(`Authentication failed: ${error.message}`);
}
}
}
module.exports = WebSocketAuth;
```
### 3. Verbindingsbeheer Klasse
```javascript
// services/ConnectionManager.js
class ConnectionManager {
constructor() {
this.connections = new Map();
this.userConnections = new Map(); // userID -> Set van connectionIDs
}
async addConnection(ws, userID, connectionID) {
// Track per gebruiker
if (!this.userConnections.has(userID)) {
this.userConnections.set(userID, new Set());
}
this.userConnections.get(userID).add(connectionID);
// Track algemene verbinding
this.connections.set(connectionID, {
ws,
userID,
connectedAt: Date.now(),
lastActivity: Date.now(),
messageCount: 0
});
// Update Redis voor clustering
await redisClient.hset(
`user:${userID}:connections`,
connectionID,
JSON.stringify({ connectedAt: Date.now() })
);
}
async removeConnection(connectionID) {
const connection = this.connections.get(connectionID);
if (connection) {
// Verwijder uit user tracking
const userConnections = this.userConnections.get(connection.userID);
if (userConnections) {
userConnections.delete(connectionID);
if (userConnections.size === 0) {
this.userConnections.delete(connection.userID);
}
}
// Verwijder uit Redis
await redisClient.hdel(
`user:${connection.userID}:connections`,
connectionID
);
this.connections.delete(connectionID);
}
}
getConnectionsByUser(userID) {
return this.userConnections.get(userID) || new Set();
}
getActiveConnectionCount() {
return this.connections.size;
}
}
```
### 4. Throttling & Rate Limiting
```javascript
// middleware/throttle.js
class ThrottleManager {
constructor() {
this.limits = {
messagesPerMinute: 60, // 1 msg/sec
connectionsPerUser: 3, // Max 3 simultane verbindingen
connectionRate: 5 // Max 5 nieuwe verbindingen/minuut
};
}
async checkMessageLimit(userID) {
const key = `throttle:${userID}:messages`;
const current = await redisClient.get(key) || 0;
if (parseInt(current) >= this.limits.messagesPerMinute) {
throw new Error('Message rate limit exceeded');
}
// Redis atomic increment met expiry
const multi = redisClient.multi();
multi.incr(key);
multi.expire(key, 60);
await multi.exec();
return true;
}
async checkConnectionLimit(userID) {
const userConnections = connectionManager.getConnectionsByUser(userID);
if (userConnections.size >= this.limits.connectionsPerUser) {
throw new Error('Maximum simultaneous connections exceeded');
}
return true;
}
}
```
### 5. Hoofd WebSocket Implementatie
```javascript
// websocket/gateway.js
const WebSocketAuth = require('../middleware/auth');
const ConnectionManager = require('../services/ConnectionManager');
const ThrottleManager = require('../middleware/throttle');
const connectionManager = new ConnectionManager();
const throttleManager = new ThrottleManager();
function setupWebSocketGateway(wss) {
wss.on('connection', async (ws, req) => {
let connectionID = generateUUID();
let authenticatedUser = null;
try {
// Authenticatie via URL query parameter
const token = new URL(req.url, `http://${req.headers.host}`).searchParams.get('token');
if (!token) throw new Error('No token provided');
authenticatedUser = await WebSocketAuth.authenticate(token);
// Throttling checks
await throttleManager.checkConnectionLimit(authenticatedUser.id);
// Verbinding registreren
await connectionManager.addConnection(ws, authenticatedUser.id, connectionID);
console.log(`Nieuwe verbinding: ${connectionID} voor gebruiker ${authenticatedUser.id}`);
// Heartbeat setup
setupHeartbeat(ws, connectionID);
} catch (error) {
console.error('Verbindingsfout:', error.message);
ws.close(4001, `Authentication failed: ${error.message}`);
return;
}
// Message handler
ws.on('message', async (data) => {
try {
// Throttling
await throttleManager.checkMessageLimit(authenticatedUser.id);
const message = JSON.parse(data);
await handleMessage(ws, message, authenticatedUser, connectionID);
// Activity tracking
updateConnectionActivity(connectionID);
} catch (error) {
console.error('Message verwerkingsfout:', error);
ws.send(JSON.stringify({
type: 'error',
message: error.message
}));
}
});
// Cleanup bij disconnect
ws.on('close', async () => {
await connectionManager.removeConnection(connectionID);
console.log(`Verbinding verbroken: ${connectionID}`);
});
// Error handling
ws.on('error', (error) => {
console.error('WebSocket error:', error);
});
});
}
async function handleMessage(ws, message, user, connectionID) {
switch (message.type) {
case 'ping':
ws.send(JSON.stringify({ type: 'pong', timestamp: Date.now() }));
break;
case 'api_request':
// Route naar REST API backend
const response = await forwardToBackendAPI(message.payload, user);
ws.send(JSON.stringify({
type: 'api_response',
requestId: message.requestId,
data: response
}));
break;
default:
throw new Error(`Onbekend message type: ${message.type}`);
}
}
```
### 6. Health Monitoring & Scaling
```javascript
// services/MonitoringService.js
class MonitoringService {
static startHealthChecks() {
setInterval(() => {
const stats = {
activeConnections: connectionManager.getActiveConnectionCount(),
memoryUsage: process.memoryUsage(),
uptime: process.uptime(),
timestamp: Date.now()
};
// Log naar Redis voor cluster monitoring
redisClient.xadd('gateway:metrics', '*',
'connections', stats.activeConnections,
'memory', JSON.stringify(stats.memoryUsage)
);
// Cleanup idle connections (> 5 minuten inactief)
this.cleanupIdleConnections();
}, 30000); // Elke 30 seconden
}
static cleanupIdleConnections() {
const now = Date.now();
const maxIdleTime = 5 * 60 * 1000; // 5 minuten
for (const [connectionID, connection] of connectionManager.connections) {
if (now - connection.lastActivity > maxIdleTime) {
connection.ws.close(4000, 'Connection idle timeout');
}
}
}
}
```
### 7. React Native Client Implementatie
```javascript
// React Native client
import { useEffect, useRef } from 'react';
const useWebSocket = (token, onMessage) => {
const ws = useRef(null);
const reconnectTimeout = useRef(null);
const connect = () => {
try {
const wsUrl = `ws://your-gateway.com/ws?token=${token}`;
ws.current = new WebSocket(wsUrl);
ws.current.onopen = () => {
console.log('WebSocket verbonden');
// Start heartbeat
setInterval(() => {
if (ws.current?.readyState === WebSocket.OPEN) {
ws.current.send(JSON.stringify({ type: 'ping' }));
}
}, 30000);
};
ws.current.onmessage = (event) => {
const message = JSON.parse(event.data);
onMessage(message);
};
ws.current.onclose = (event) => {
console.log('WebSocket verbroken:', event.code, event.reason);
// Reconnect logica met exponential backoff
scheduleReconnect();
};
} catch (error) {
console.error('WebSocket verbindingsfout:', error);
}
};
const scheduleReconnect = () => {
clearTimeout(reconnectTimeout.current);
reconnectTimeout.current = setTimeout(() => {
connect();
}, 5000); // 5 seconden
};
useEffect(() => {
connect();
return () => {
clearTimeout(reconnectTimeout.current);
if (ws.current) {
ws.current.close();
}
};
}, [token]);
return ws;
};
```
## Schaaltips voor 500+ Verbindingen
1. **Cluster Ondersteuning**: Gebruik Redis pub/sub voor inter-process communicatie
2. **Load Balancing**: Implementeer round-robin DNS of gebruik een load balancer
3. **Connection Pooling**: Gebruik database connection pools voor backend communicatie
4. **Memory Management**: Regelmatige cleanup van oude verbindingen
5. **Monitoring**: Implementeer uitgebreide logging en metrics
## Beveiligingsmaatregelen
- JWT signature verificatie
- Rate limiting per gebruiker
- Input validatie en sanitization
- SSL/TLS encryptie (wss://)
- Regular security dependency updates
Deze architectuur biedt een solide basis voor een schaalbare en veilige WebSocket API gateway die perfect aansluit bij je Node.js/Express backend en React Native frontend.
error: Generation failed [deepseek] prompt_id=4195 locale=en err=DeepSeek connection/timeout | Generation failed [deepseek] prompt_id=4195 locale=fr err=DeepSeek connection/timeout | Generation failed [deepseek] prompt_id=4195 locale=es err=DeepSeek connection/timeout