NodeJS 如何代理 ws 协议的请求?

发布于 1周前 作者 yibo5220 来自 nodejs/Nestjs

背景:使用 NodeJS 实现一个代理服务器,把服务器 URL 设置为电脑的全局代理,这样浏览器访问链接,把流量劫持到代理服务器,如何实现代理 http 协议和 ws 协议?比如在浏览器访问 a.com ,可以被代理服务器转发的 b.com ;访问 ws://a.com 可以被转发到 ws://127.0.0.1:8000 目前实现:

const http = require('http');
const httpProxy = require('http-proxy');

// 创建一个代理服务器 const proxy = httpProxy.createProxyServer({ ws: true, // 启用 WebSocket 支持 changeOrigin: true // 修改源 });

// 创建 HTTP 服务器 const server = http.createServer((req, res) => { console.log(收到 HTTP 请求: ${req.method} ${req.url}); // 处理 HTTP 请求 proxy.web(req, res, { target: ‘http://localhost:8080’ }, (err) => { if (err) { console.error(HTTP 代理错误: ${err.message}); } }); });

// 处理 WebSocket 连接 server.on(‘upgrade’, (req, socket, head) => { console.log(收到 WebSocket 升级请求: ${req.url}); proxy.ws(req, socket, head, { target: ‘ws://localhost:8080’ }, (err) => { if (err) { console.error(WebSocket 代理错误: ${err.message}); } }); });

// 设置代理服务器监听的端口 const PORT = 8002;

server.listen(PORT, () => { console.log(代理服务器已启动,正在监听端口 ${PORT}); });

// 错误处理 proxy.on(‘error’, (err, req, res) => { console.error(‘代理服务器错误:’, err); if (!res.headersSent) { res.writeHead(500, { ‘Content-Type’: ‘text/plain’ }); } res.end(‘代理服务器出错’); });

// 添加代理事件监听器 proxy.on(‘proxyReq’, (proxyReq, req, res) => { console.log(代理请求: ${req.method} ${req.url} -> ${proxyReq.path}); });

proxy.on(‘proxyRes’, (proxyRes, req, res) => { console.log(代理响应: ${req.url} - 状态码: ${proxyRes.statusCode}); });

在浏览器使用 SwitchyOmega ,设置代理 http://1270.0.0.1:8002

访问 http 请求:get http://t.weather.sojson.com/api/weather/city/101030100 可以看到打印日志

收到 HTTP request 请求: GET http://t.weather.sojson.com/api/weather/city/101030100

但是访问 ws 请求:ws://t.weather.sojson.com 没有打印任何日志,也就是说 upgrade 事件并没有触发。

问 AI ,回答可能是 WebSocket 握手过程中的协议升级可能在代理服务器之前就已经完成了。代理服务器可能只是在转发已经建立的 WebSocket 连接,而没有参与到协议升级的过程中。

有没有大佬帮忙分析下? ps: 在设置自签名证书后,可以代理 https 协议和 wss 协议,但是就是 ws 协议没反应。


NodeJS 如何代理 ws 协议的请求?

6 回复

上周刚写的,我用的 VITE

server: {
// 端口号
port: VITE_PORT,
host: “0.0.0.0”,
// 本地跨域代理 https://cn.vitejs.dev/config/server-options.html#server-proxy
proxy: {
“/api”: {
// 这里填写后端地址
target: http://127.0.0.1:8080,
changeOrigin: true,
rewrite: path => path.replace(/^/api/, “/api/”)
},
“/socket”: {
target: “ws://127.0.0.1:8080”,
changeOrigin: true,
ws: true
}
},
// 预热文件以提前转换和缓存结果,降低启动期间的初始页面加载时长并防止转换瀑布
warmup: {
clientFiles: ["./index.html", “./src/{views,components}/*”]
}
},


我主要问题是代理服务器接受不到浏览器 ws 请求的流量,如果直接访问 ws://127.0.0.1:8002 ,是没问题的

建议 Clash -> 你的程序
这种 因为 http 代理并不支持 ws ,windows 应该也不支持直接配置 socks5
所以前边套个 clash

奇怪的是,wss 请求是可以代理的

思路比较混乱,ws 最少给不同的(子)域名,最差也要给一个路径,如果不区分只能在 程序逻辑中实现了,相当麻烦。

在 Node.js 中代理 WebSocket (ws) 协议的请求通常可以使用 ws 库和 http-proxy 库来实现。以下是一个简单的示例,展示了如何设置一个 WebSocket 代理服务器。

首先,确保你已经安装了所需的库:

npm install ws http-proxy

然后,你可以创建一个代理服务器,如下所示:

const WebSocket = require('ws');
const http = require('http');
const httpProxy = require('http-proxy');

const proxy = httpProxy.createProxyServer({ changeOrigin: true });

// 创建 WebSocket 服务器
const server = http.createServer((req, res) => {
  res.writeHead(200, { 'Content-Type': 'text/plain' });
  res.end('WebSocket proxy server\n');
});

server.on('upgrade', (req, socket, head) => {
  console.log('Proxying WebSocket connection...');
  proxy.ws(req, socket, head, { target: 'ws://your-target-websocket-server' });
});

server.listen(3000, () => {
  console.log('WebSocket proxy server listening on port 3000');
});

proxy.on('error', (err, req, res) => {
  console.error('Proxy error:', err);
});

在这个示例中,我们创建了一个 HTTP 服务器,并监听 upgrade 事件以处理 WebSocket 升级请求。当 WebSocket 升级请求到来时,我们使用 proxy.ws 方法将其代理到目标 WebSocket 服务器(ws://your-target-websocket-server)。

确保将 ws://your-target-websocket-server 替换为你实际想要代理到的 WebSocket 服务器地址。

这个简单的代理服务器将能够处理 WebSocket 协议的请求,并将其转发到指定的目标服务器。

回到顶部