Simple node.js proxy by piping http server to http

2019-01-22 09:11发布

Trying to learn more about node.js by making a simple http proxy server. The use scenario is simple: user -> proxy -> server -> proxy -> user

The following code works until the last step. Couldn't find way to pipe connector's output back to the user.

#!/usr/bin/env node

var
    url = require('url'),
    http = require('http'),
    acceptor = http.createServer().listen(3128);

acceptor.on('request', function(request, response) {
    console.log('request ' + request.url);
    request.pause();
    var options = url.parse(request.url);
    options.headers = request.headers;
    options.method = request.method;
    options.agent = false;

    var connector = http.request(options);
    request.pipe(connector);
    request.resume();
//  connector.pipe(response); // doesn't work
//  connector.pipe(request); // doesn't work either
});

Using tcpflow I see the incoming request from the browser, then the outgoing proxy request, then the server response back to the proxy. Somehow i couldn't manage to retransmit the response back to the browser.

What is the proper way to implement this logic with pipes?

3条回答
爷的心禁止访问
2楼-- · 2019-01-22 09:24

I used the examples from this post to proxy http/s requests. Faced with the problem that cookies were lost somewhere.

So to fix that you need to handle headers from the proxy response.

Below the working example:

req = service.request(options, function(res) {
    response.writeHead(res.statusCode, res.headers);
    return res.pipe(response, {end: true});
});
request.pipe(req, {end: true});
查看更多
【Aperson】
3楼-- · 2019-01-22 09:31

OK. Got it.

UPDATE: NB! As reported in the comments, this example doesn't work anymore. Most probably due to the Streams2 API change (node 0.9+)

Piping back to the client has to happen inside connector's callback as follows:

#!/usr/bin/env node

var
    url = require('url'),
    http = require('http'),
    acceptor = http.createServer().listen(3128);

acceptor.on('request', function(request, response) {
    console.log('request ' + request.url);
    request.pause();
    var options = url.parse(request.url);
    options.headers = request.headers;
    options.method = request.method;
    options.agent = false;

    var connector = http.request(options, function(serverResponse) {
            serverResponse.pause();
            response.writeHeader(serverResponse.statusCode, serverResponse.headers);
            serverResponse.pipe(response);
            serverResponse.resume();
    });
    request.pipe(connector);
    request.resume();
});
查看更多
你好瞎i
4楼-- · 2019-01-22 09:46

you dont have to 'pause', just 'pipe' is ok

var connector = http.request(options, function(res) {
  res.pipe(response, {end:true});//tell 'response' end=true
});
request.pipe(connector, {end:true});

http request will not finish until you tell it is 'end';

查看更多
登录 后发表回答