Closed OpportunityLiu closed 1 year ago
Can you share your code?
Here is a simple repro:
proxy.js
import * as http from 'http';
import { createProxy } from 'proxy';
const server = createProxy(http.createServer());
server.listen(3128, () => {
var port = server.address().port;
console.log('HTTP(s) proxy server listening on port %d', port);
});
server.js
import { createServer } from 'node:http';
import { WebSocketServer } from 'ws';
const s = createServer((req, res) => {
console.log('request', req.url, req.headers);
res.writeHead(200, { 'Content-Type': 'text/plain' });
res.end('okay');
});
s.listen(8080);
const wss = new WebSocketServer({ server: s });
wss.on('listening', () => {
console.log('Ws server listening');
});
wss.on('connection', (ws, req) => {
console.log('connected', req.url, req.headers);
});
client.js
import { WebSocket } from 'ws';
import { ProxyAgent } from 'proxy-agent';
const ws1 = new WebSocket('ws://localhost:8080/ws1');
process.env['http_proxy'] = 'http://localhost:3128';
process.env['https_proxy'] = 'http://localhost:3128';
process.env['no_proxy'] = '';
const agent = new ProxyAgent();
const ws2 = new WebSocket('ws://localhost:8080/ws2', { agent });
Start server.js
and proxy.js
, then run client.js
.
In server.js
, you will get:
Ws server listening
connected /ws1 {
'sec-websocket-version': '13',
'sec-websocket-key': 'b3x5PQrzBDcfjKK7T9ndXQ==',
connection: 'Upgrade',
upgrade: 'websocket',
'sec-websocket-extensions': 'permessage-deflate; client_max_window_bits',
host: 'localhost:8080'
}
request /ws2 {
'sec-websocket-version': '13',
'sec-websocket-key': '2dCSx8sD4wUmNCXAENRoRA==',
'sec-websocket-extensions': 'permessage-deflate; client_max_window_bits',
host: 'localhost:8080',
'proxy-connection': 'close',
'x-forwarded-for': '::ffff:127.0.0.1',
via: '1.1 xxx (proxy/2.1.1)',
connection: 'close'
}
indicates that connection without proxy-agent
(/ws1
) is handled successfully by server, while /ws2
is handled as a plain http request.
In client.js
, you will get:
node:events:491
throw er; // Unhandled 'error' event
^
Error: Unexpected server response: 200
at ClientRequest.<anonymous> (...\node_modules\ws\lib\websocket.js:888:7)
at ClientRequest.emit (node:events:513:28)
at HTTPParser.parserOnIncomingClient (node:_http_client:693:27)
at HTTPParser.parserOnHeadersComplete (node:_http_common:128:17)
at Socket.socketOnData (node:_http_client:534:22)
at Socket.emit (node:events:513:28)
at addChunk (node:internal/streams/readable:315:12)
at readableAddChunk (node:internal/streams/readable:289:9)
at Socket.Readable.push (node:internal/streams/readable:228:10)
at TCP.onStreamRead (node:internal/stream_base_commons:190:23)
Emitted 'error' event on WebSocket instance at:
at emitErrorAndClose (...\node_modules\ws\lib\websocket.js:1008:13)
at processTicksAndRejections (node:internal/process/task_queues:83:21)
Currently a workaround is always to use https-proxy-agent
for http proxies.
import { proxies } from 'proxy-agent';
proxies['http'][0] = proxies['http'][1];
proxies['https'][0] = proxies['https'][1];
Fixed in proxy-agent@6.2.1
.
a simple example can be found here too - https://gist.github.com/ttodua/7a66e5ca28e55deebc58b0dd8e0c39a2
Since proxies will drop hop-by-hop headers (
Connect
andUpgrade
), we cannot usehttp-proxy-agent
to connect to a web socket. But when I useproxy-agent
, it will sendws:
requests viahttp-proxy-agent
.