2012-11-20 115 views
12

试图通过制作一个简单的http代理服务器来了解关于node.js的更多信息。使用场景很简单:用户 - >代理 - >服务器 - >代理 - >用户简单的node.js代理通过将http服务器管道到http请求

以下代码可用,直到最后一步。无法找到管道连接器的输出回到用户的方式。

#!/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我看到来自浏览器的传入请求,然后传出代理请求,然后服务器响应回代理。不知何故,我无法将重新传输回浏览器。

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

回答

19

好的。得到它了。

更新:注意!正如评论中所报道的那样,这个例子不再适用。最有可能是由于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(); 
}); 
+0

-1,因为:stream.js:94 抛儿; //管道中未处理的流错误。 ^ 错误:连接ECONNREFUSED at errnoException(net.js:901:11) at Object.afterConnect [as oncomplete](net.js:892:19) –

+3

@rob,很可能这个例子不适用于新的Streams2 API。 Streams2在节点0.9中作为beta引入,并在0.10分支中稳定运行。 0.10于2013年3月发布 - 本次讨论后的几​​个月。所以,如果你真的想要更有建设性,而不是把-1s,适应新的API的例子。 –

+0

@NikolaiGorchilov上面的例子在节点0.10.13中为我工作。只有改变我不得不做的是'response.writeHead'而不是'response.writeHeader' – Gireesh

19

你没有“暂停”,只是“管”是好的

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

http请求将不会完成,直到你告诉它'结束';

+4

{end:true}是一个很好的建议。 10X。 关于暂停,我仍然认为最好使用它。设想一个用户使用HTTP POST上传大文件。为什么在传出连接正在构建时,他的文件会缓存在服务器的RAM中?而如果这种传出连接由于某种原因而不可能呢? –

+1

FWIW,现代节点不再需要'{end:true}' - 默认值为'true',所以如果禁用,只需要传递选项。 – Jesse

1

我用这个帖子的例子来代理http/s请求。面对饼干在某处丢失的问题。

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

下面的工作示例:

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