在http-proxy-middleware中捕获响应的问题

前端开发 2026-07-10

我正在编写一个代理,用来将WebSocket消息转发到后端服务器。

客户端通过HTTP发起请求,升级为WebSocket,并使用Sec-WebSocket-Key头。代理需要拦截该请求,为请求添加额外的头部,然后将请求转发给后端服务。

后端将接受升级请求,并返回一个Sec-WebSocket-Accept头,以及一个request-Id头。

在此通信过程中,我需要拦截响应,并获取后端服务返回的request-Id。

我已经编写了这段代码来获取request-Id。发起请求时,我可以在开发者工具的网络选项卡中看到来自 proxyReqWs 钩子的日志,但在网络选项卡中没有看到来自 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 请求头 的 日志。代理应该已经拦截了响应并修改了头部名称,但并未发生。

这段代码里我还缺少什么?我需要修改响应头。

// 代理.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);
};

// 服务器.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;

我应该如何修复这个代理,以便在拦截它们之后同时拦截请求和响应,并在拦截后调用外部服务?

解决方案

proxyRes 仅用于HTTP流量,拦截WebSocket响应不被支持:

Websocket response interceptor? #635

可能的变通办法:

新增拦截和操作WebSocket消息的能力#991

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

站内所有文章版权归属LeftHeroAI导航站,无授权禁止任何主体转载、抄袭、复制内容,亦不得私自架设镜像站点。一经侵权,本站将通过法律途径追责。

相关文章