在使用 http-proxy-middleware 代理到 websocket 服务器之前,如何进行一些验证?
Posted
技术标签:
【中文标题】在使用 http-proxy-middleware 代理到 websocket 服务器之前,如何进行一些验证?【英文标题】:How can I involve some validation before proxying to a websocket server with http-proxy-middleware? 【发布时间】:2021-09-01 22:37:34 【问题描述】:我可能搞错了。
目标:通过 apache 接收 https 连接,并在将其路由到 websocket 服务器之前进行一些验证。如果无效则返回 403 状态码,如果有效则继续进行 websocket 连接。
我决定尝试为此使用基于 http-proxy-middleware 的节点代理。在 apache 中,我有一个虚拟主机条目,其中包括:
<Location /testws>
ProxyPass ws://127.0.0.1:6006/testws
ProxyPassReverse ws://127.0.0.1:6006/testws
</Location>
我在 6006 端口上运行的节点代理是:
const express = require('express');
const createProxyMiddleware, responseInterceptor = require('http-proxy-middleware');
const app = express();
// proxy middleware options
const wsProxyOptions =
target: 'http://example.org', // target host
changeOrigin: true, // needed for virtual hosted sites
ws: true, // proxy websockets
router:
// when request.headers.host == 'dev.localhost:3000',
// override target 'http://www.example.org' to 'http://localhost:8000'
// 'dev.localhost:3000': 'http://localhost:8000',
'/testws': 'ws://127.0.0.1:6082', //my websocket server is running on port 6082
,
selfHandleResponse: true,
onProxyRes: responseInterceptor(async (responseBuffer, proxyRes, req, res) =>
res.statusCode = 418; // set different response status code
const response = responseBuffer.toString('utf8');
return response.replace('Example ', 'NewText');
),
logLevel: 'debug'
;
// The setup below is recommended for external websocket upgrades
// https://github.com/chimurai/http-proxy-middleware#external-websocket-upgrade
const wsProxy = createProxyMiddleware(wsProxyOptions);
app.use(wsProxy);
const server = app.listen(6006);
server.on('upgrade', wsProxy.upgrade); // optional: upgrade externally
当我使用该设置时,我会从浏览器转到https://server.ip/testws。我按预期路由到我的 websocket 服务器。但是, onProxyRes(responseInterceptor) 永远不会被访问。我还尝试了其他事件选项,例如 onProxyReq 和 onProxyReqWs。他们也不会被击中。
接下来,我尝试将 apache 设置中的 ProxyPass 和 ProxyPassReverse 设置更改为 http://127.0.0.1:6006/testws 而不是 ws://127.0.0.1:6006/testws。现在,onProxyReq 确实被访问了,但是我从我的 websocket 服务器得到了一个响应,说“需要升级”,这可能是有道理的,因为升级还没有发生。可以在这里升级连接吗?如果有,怎么做?
我一直在尝试的另一件事是涉及路由器选项的异步功能。这对我来说可以确定新目标应该是什么,但似乎没有办法从那里涉及状态代码,因为它只想要返回一个目标值。
我想尝试 responseInterceptor 的原因是因为我想在连接到我的 websocket 服务器之前进行一些验证,如果验证失败,则返回状态代码 403,而不是继续使用 websocket 连接。对此有什么想法吗?或者,对于我正在尝试做的事情,这是错误的方法吗?
更新:我想我不需要 onProxyRes 是有道理的,因为升级可能在此之前发生。我仍然不确定为什么 onProxyReq 选项不起作用。不管怎样,我开始看:
server.on('upgrade', wsProxy.upgrade);
如果验证失败,我能否以某种方式回复状态码?例如:
server.on('upgrade', (req, socket, head) =>
if (valid)
wsProxy.upgrade(req, socket, head);
else
//somehow return status 403
);
【问题讨论】:
【参考方案1】:看起来这篇文章问的是同样的事情,但更清楚:
Intercept (and potentially deny) web socket upgrade request
我不确定是否有更合适的解决方案,但到目前为止提到的解决方案似乎对我有用。它基本上展示了如何在升级时使用 http 状态代码进行响应:
server.on('upgrade', (req, socket, head) =>
if (validationPasses)
wsProxy.upgrade(req, socket, head);
else
socket.write('HTTP/1.1 403 Access Denied\r\n' +
'Upgrade: WebSocket\r\n' +
'Connection: Upgrade\r\n' +
'\r\n');
socket.destroy();
return;
);
【讨论】:
以上是关于在使用 http-proxy-middleware 代理到 websocket 服务器之前,如何进行一些验证?的主要内容,如果未能解决你的问题,请参考以下文章
在使用 http-proxy-middleware 代理到 websocket 服务器之前,如何进行一些验证?
使用axios以及http-proxy-middleware代理处理跨域的问题
React18使用 http-proxy-middleware代理跨域
插件http-proxy-middleware在vue-cli中的使用