node.js http.request事件流 - 我的END事件在哪里?

时间:2011-06-04 01:09:24

标签: javascript proxy node.js connect coffeescript

我正在制定一项狡猾的计划,该计划涉及将node.js用作另一项服务前的代理服务器。

简而言之:

  1. 将传入的请求发送到静态文件(如果存在)
  2. 否则,将请求发送给其他服务
  3. 我有基础工作,但现在试图让整个事情与Sencha Connect一起工作,这样我就可以访问所提供的所有kick-ass中间件。

    所有操作都发生在 dispatchProxy 下面

    connect(
      connect.logger(), 
      connect.static(__dirname + '/public'),
      (request, response) ->  
        dispatchProxy(request, response)
    ).listen(8000)
    
    dispatchProxy = (request, response) ->  
    
      options = {host: host, port: port, method: request.method, headers: request.headers, path: request.url}
    
      proxyRequest = http.request(options, (proxyResponse) ->
        proxyResponse.on('data', (chunk) ->
         response.write(chunk, 'binary')
        )
    
        proxyResponse.on('end', (chunk) ->        
         response.end()
        )
    
        response.writeHead proxyResponse.statusCode, proxyResponse.headers    
      )
    
      request.on('data', (chunk) ->
        proxyRequest.write(chunk, 'binary')
      )
    
      # this is never triggered for GETs
      request.on('end', ->
        proxyRequest.end()
      )
    
      # so I have to have this here
      proxyRequest.end()
    

    您会在上面的最后一行注意到 proxyRequest.end()

    我发现在处理GET请求时,永远不会触发请求的END事件,因此需要调用proxyRequest.end()。 POST请求按预期触发DATA和END事件。

    所以有几个问题:

    • 对proxyRequest.end()的调用是否安全?也就是说,即使在事件循环之外调用proxyResponse,它仍然会完成吗?

    • GET不触发END事件是正常的,还是在连接堆栈的某处捕获了END?

2 个答案:

答案 0 :(得分:4)

问题少于end事件和data事件。如果客户端发出GET请求,则表示没有数据。这与请求者发送数据的POST不同,因此on("data")处理程序被命中。所以(原谅我的JS例子,我对coffeescript并不熟悉):

var http = require('http');

// You won't see the output of request.on("data")
http.createServer(function (request, response) {
  request.on("end", function(){
    console.log("here");
  });
  request.on("data", function(data) {
    console.log("I am here");
    console.log(data.toString("utf8"));
  });
  response.writeHead(200, {'Content-Type': 'text/plain'});
  response.end('Hello World\n');
}).listen(8124);

console.log('Server running at http://127.0.0.1:8124/');

如果我对此服务器进行curl调用,则数据事件永远不会被命中,因为GET请求只不过是标题。因此,您的逻辑变为:

// okay setup the request...
// However, the callback doesn't get hit until you
// start writing some data or ending the proxyRequest!
proxyRequest = http.request(options, (proxyResponse) ->
  // So this doesn't get hit yet...
  proxyResponse.on('data', (chunk) ->
   response.write(chunk, 'binary')
  )

  // and this doesn't get hit yet
  proxyResponse.on('end', (chunk) ->
   // which is why your response.on("end") event isn't getting hit yet        
   response.end()
  )

  response.writeHead proxyResponse.statusCode, proxyResponse.headers    
)

// This doesn't get hit!
request.on('data', (chunk) ->
  proxyRequest.write(chunk, 'binary')
)

// So this isn't going to happen until your proxyRequest
// callback handler gets hit, which hasn't happened because
// unlike POST there's no data in your GET request
request.on('end', ->
  proxyRequest.end()
)

// now the proxy request call is finally made, which
// triggers the callback function in your http request setup
proxyRequest.end()

所以是的,由于我刚刚提到的逻辑分支,你将不得不为proxyRequest.end()请求手动调用GET

答案 1 :(得分:0)

我的经验是request.on('end',)不是始终调用,除非它是POST。我怀疑(有人制作http.request)的事件已经结束,然后脚本才有机会检测到它。