【问题标题】:Simple node.js proxy by piping http server to http request通过将 http 服务器传送到 http 请求的简单 node.js 代理
【发布时间】:2012-11-08 10:48:50
【问题描述】:

尝试通过制作一个简单的 http 代理服务器来了解有关 node.js 的更多信息。使用场景很简单:用户->代理->服务器->代理->用户

以下代码一直有效,直到最后一步。找不到将连接器的输出通过管道传回给用户的方法。

#!/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
});

使用 tcpflow 我看到来自浏览器的传入请求,然后是传出代理请求,然后是服务器对代理的响应。不知何故,我无法将响应重新传输回浏览器。

用管道实现这个逻辑的正确方法是什么?

【问题讨论】:

    标签: node.js http proxy


    【解决方案1】:

    您不必“暂停”,只需“管道”即可

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

    http 请求在你告诉它“结束”之前不会完成;

    【讨论】:

    • {end:true} 是一个不错的建议。 10 倍。关于暂停,我还是觉得用它比较好。想象一个用户使用 HTTP POST 上传一个大文件。为什么在构建传出连接时,他的文件会缓冲在服务器的 RAM 中?如果由于某种原因无法进行传出连接怎么办?
    • FWIW,现代节点不再需要{ end: true } - 默认为true,因此您只需在禁用时传递选项。
    【解决方案2】:

    好的。明白了。

    更新:注意!正如 cmets 中所报告的,此示例不再适用。很可能是由于 Streams2 API 更改(节点 0.9+)

    返回客户端的管道必须在连接器的回调中进行,如下所示:

    #!/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();
    });
    

    【讨论】:

    • -1 因为:stream.js:94 throw er; // 管道中未处理的流错误。 ^ 错误:在 Object.afterConnect 的 errnoException (net.js:901:11) 处连接 ECONNREFUSED [as oncomplete] (net.js:892:19)
    • @rob,这个例子很可能不适用于新的 Streams2 API。 Streams2 在节点 0.9 中作为 beta 引入,并在 0.10 分支中稳定。 0.10 于 2013 年 3 月发布 - 讨论后几个月。因此,如果您真的想要更具建设性,而不是使用 -1,请针对新 API 调整示例。
    • @NikolaiGorchilov 上面的例子对我来说适用于节点 0.10.13。我唯一需要做的改变是response.writeHead 而不是response.writeHeader
    • 能否请您给stackoverflow.com/questions/22684644/…一些建议,我将不胜感激:)
    • 我拿着它跑了:gist.github.com/cmawhorter/a527a2350d5982559bb6希望有人觉得它有用。
    【解决方案3】:

    我使用这篇文章中的示例来代理 http/s 请求。面对 cookie 在某处丢失的问题。

    因此,要解决此问题,您需要处理来自代理响应的标头。

    在工作示例下方:

    req = service.request(options, function(res) {
        response.writeHead(res.statusCode, res.headers);
        return res.pipe(response, {end: true});
    });
    request.pipe(req, {end: true});
    

    【讨论】:

    • 请求回调中的“响应”是什么?你从哪里来的“请求”?
    猜你喜欢
    • 2012-03-23
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-10-31
    • 2013-05-30
    • 1970-01-01
    • 2020-05-03
    相关资源
    最近更新 更多