1

I am writing a proxy to relay websocket messages to a backend server.

Client initiates a request over HTTP to upgrade to WS using a Sec-WebSocket-Key header. The proxy has to intercept the request and add additional headers to the request and relay the request to backend service.

Backend will accept the upgrade request and will return a Sec-WebSocket-Accept header along with a request-Id header.

During this communication I need to intercept the response and get the request-id returned from the Backend service.

I have written this code to get the request-id. When I initiate the request I can see logs from proxyReqWs hook but I don't see any logs from proxyRes` hook. I can see that the proxy has relayed the response to the client as I can see Sec-Websocket-Accept and xyz-req-id headers in the Network tab in Developer Console. The proxy should have intercepted the response and changed the header names, but that has not happened.

What am I missing in this code? I need to change the response header.

// proxy.js

export const setupProxy = (proxyConfig: ProxyConfig): RequestHandler => {
    const proxyOptions: Options = {
        target: proxyConfig.endpoint,
        changeOrigin: true,
        secure: true, 
        ws: true,
        on: {
            proxyReq: (proxyReq, req, res) => {
                log('--------------------------------------');
                logRequest(req as Request, 'Original Request from Client'); // Log original client request

                proxyReq.setHeader('Authorization', `Bearer ${proxyConfig.details.apiKey}`);

                logRequest(proxyReq, 'MODIFIED request to Backend)'); // Log modified request
            },
            proxyRes: (proxyRes, req, res) => {
                logResponse(proxyRes, req as Request, 'Original Response from Backend'); // Log response from Backend
                const isWebSocketSuccess = proxyRes.statusCode === 101;
                let requestId: string | undefined;
                if(isWebSocketSuccess) {
                    const requestId = proxyRes.headers['xyz-req-id'];
                }

                if (requestId) {
                    log(requestId);
                    proxyRes.headers['x-xyz-request-id'] = requestId;
                }

                delete proxyRes.headers['xyz-req-id'];

                logResponse(proxyRes, req as Request, 'MODIFIED response to Client)'); // Log modified response
                log('--------------------------------------');
            },
            proxyReqWs: (proxyReq, req, socket, options, head) => {
                log('proxyReqWs event triggered for:', { method: req.method, url: req.url });
                proxyReq.setHeader('Authorization', `Bearer ${proxyConfig.details.apiKey}`);
            },
            error: (err, req, res) => {
                logError('Proxy Error:', err.message, 'Target:', target);
                if (res.writeHead && !res.headersSent) {
                    res.writeHead(502, { 'Content-Type': 'application/json' });
                    res.end(JSON.stringify({ error: 'Bad Gateway', message: err.message }));
                }
            }
        },
        router: (req) => {
            return proxyConfig.endpoint;
        }
    };

    return createProxyMiddleware(proxyOptions);
};

// server.js

import express from 'express';
import { setupProxy  } from './proxy';
import config from './config';
import http from 'http';

const app = express();
const PORT = config.port;

// --- Express Middleware ---
// --- Health Check Endpoint ---
app.get('/health', (req, res) => {
    console.log('Health Check Request Received');
    res.status(200).send('Proxy is healthy!');
});

const proxy = setupProxy(config);
app.use('/', proxy);

// --- Start the Server ---
const server = http.createServer(app);

server.on('upgrade', proxy.upgrade);

server.listen(PORT, () => {
    console.log(`[SERVER] Express Proxy listening on port ${PORT}`);
    console.log(`[SERVER] Forwarding requests to Backend endpoint: ${config.endpoint}`);
});

// Handle server errors
server.on('error', (error: NodeJS.ErrnoException) => {
    if (error.syscall !== 'listen') {
        throw error;
    }

    const bind = typeof PORT === 'string' ? 'Pipe ' + PORT : 'Port ' + PORT;

    // handle specific listen errors with friendly messages
    switch (error.code) {
        case 'EACCES':
            console.error(`${bind} requires elevated privileges`);
            process.exit(1);
            break;
        case 'EADDRINUSE':
            console.error(`${bind} is already in use`);
            process.exit(1);
            break;
        default:
            throw error;
    }
});

export default app; 

How should I fix this proxy so that I can intercept both request and response and call an external service after intercepting them?

1 Answer 1

1

proxyRes is for HTTP traffic, intercepting websocket response is not supported:

Websocket response interceptor? #635

possible workarounds:

Added ability to intercept and manipulate web socket messages #991

[ws] add options to transform client and server streams #1301

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.