Node.js NodeJS-如何在没有缓冲的情况下对请求正文进行流式处理

Node.js NodeJS-如何在没有缓冲的情况下对请求正文进行流式处理,node.js,http,stream,pipe,epipe,Node.js,Http,Stream,Pipe,Epipe,在下面的代码中,我无法理解为什么req.pipe(res)不工作,但也没有抛出错误。直觉告诉我这是由于nodejs的异步行为,但这是一个没有回调的非常简单的情况 我错过了什么 http.createServer(function (req, res) { res.writeHead(200, { 'Content-Type': 'text/plain' }); res.write('Echo service: \nUrl: ' + req.url); res.write('\n

在下面的代码中,我无法理解为什么req.pipe(res)不工作,但也没有抛出错误。直觉告诉我这是由于nodejs的异步行为,但这是一个没有回调的非常简单的情况

我错过了什么

http.createServer(function (req, res) {

  res.writeHead(200, { 'Content-Type': 'text/plain' });

  res.write('Echo service: \nUrl:  ' + req.url);
  res.write('\nHeaders:\n' + JSON.stringify(req.headers, true, 2));

  res.write('\nBody:\n'); 

  req.pipe(res); // does not work

  res.end();

}).listen(8000);
这是卷曲:

➜  ldap-auth-gateway git:(master) ✗ curl -v -X POST --data "test.payload" --header "Cookie:  token=12345678" --header "Content-Type:text/plain" localhost:9002 
以下是调试输出(请参见上传的正文):

服务响应而不回显请求主体:

Echo service: 
Url:  /
Headers:
{
  "user-agent": "curl/7.24.0 (x86_64-apple-darwin12.0) libcurl/7.24.0 OpenSSL/0.9.8x zlib/1.2.5",
  "host": "localhost:9002",
  "accept": "*/*",
  "cookie": "token=12345678",
  "content-type": "text/plain",
  "content-length": "243360",
  "expect": "100-continue"
}
。。。最后一个curl调试是

Body:
 Connection #0 to host localhost left intact
 Closing connection #0
此外,当我使用大型请求体进行压力测试时,我会得到一个EPIPE错误。我怎样才能避免这种情况

--编辑:通过反复试验,我确实做到了这一点,但它仍然指向一个时间问题。虽然这仍然很奇怪,因为超时会导致返回有效负载,但超时持续时间并不重要。换句话说,无论我将超时设置为5秒还是500秒,有效负载都会正确地通过管道传回请求并终止连接

以下是编辑:

http.createServer(function (req, res) {

    try {
      res.writeHead(200, { 'Content-Type': 'text/plain' });
      res.write('Echo service: ' + req.url + '\n' + JSON.stringify(req.headers, true, 2));
      res.write('\nBody:"\n');
      req.pipe(res);
    } catch(ex) {
      console.log(ex);
      // how to change response code to error here?  since headers have already been written?
    } finally {
      setTimeout((function() {
        res.end();
      }), 500000);
    }

}).listen(TARGET_SERVER.port);

?管道req到res。req是可读流,响应是可写流。它应该可以工作

   http.createServer(function (req, res) {

       res.writeHead(200, { 'Content-Type': 'text/plain' });    
       res.write('Echo service: ' + req.url + '\n' + JSON.stringify(req.headers, true, 2));

       // pipe request body directly into the response body
       req.pipe(res);       

   }).listen(9002);

因此,首先,看起来您的curl已关闭,发布数据的文件名前面应该有@。否则,您只需发布文件名

除此之外,Chandu说调用
res.end()
是这里的问题是正确的

由于IO在节点中是异步的,所以当您发出
.pipe
命令时,当管道在后台工作时,控制会立即返回到当前上下文。下次调用
res.end()
时,关闭流

这里的解决方案是让
.pipe
结束流本身

我可以想象,由于在不同的机器和不同的数据大小上,异步IO理论上可以在可写流上的结束事件完全处理之前完成(小数据集的快速IO)


我建议您提供更多信息。

注意,您将看到向9002发出了请求。这是一个反向代理(目标为8000的简单节点http代理)。直接命中目标也会产生同样的结果。这会起作用。。。有时。。。管道调用有一些异步的地方。机器速度越快,这一点就越经常不起作用。通过在调用res.end()之前等待,我可以让它工作。悬赏是给任何人的,谁能解释为什么我能通过增加睡眠来解决这个问题。(请参阅问题底部的编辑)管道调用负责在req流调用close/end时调用res.end。管道传输后无需再次调用res.end。您是否在未使用res.end()的情况下尝试了上述代码?添加睡眠后代码仍能正常工作(在nodejs:-)的原因是管道实际上在请求流结束后有时间关闭响应流。res.end()在settimeout中,只是关闭关闭的流。接受您的答案,但包括Wyatt的部分答案,因为Wyatt更详细地解释了原因:由于IO在节点中是异步的,所以当您发出.pipe命令时,控件会立即返回到当前上下文,而管道在后台工作。下次调用res.end()时,将关闭流,从而阻止写入更多数据。这里的解决方案是让.pipe结束流本身,这是默认的。为什么
req.pipe(res)
工作?它如何知道只发送
req.body
,而不是发送所有的头等等?这很有道理。谢谢你的解释。你是卷发贴。这是故意的,因为我两者都在做。。取下@来测试文件中包含的相对较大的有效负载中的几个字符。因此,如果我能理解“有趣的”超时行为。。。管道需要500毫秒,然后关闭连接。超时仍然会发生(即使设置为500秒以后),但在调用res.close时,它不会做任何事情,因为res已经关闭。我希望报告某种错误。提出错误肯定会有用。。虽然这里可能还有别的事情在起作用。我只是尝试在调用
end
后添加一些
res.write
s,但它们也失败了。他们应该抛出错误。真有趣。。!
   http.createServer(function (req, res) {

       res.writeHead(200, { 'Content-Type': 'text/plain' });    
       res.write('Echo service: ' + req.url + '\n' + JSON.stringify(req.headers, true, 2));

       // pipe request body directly into the response body
       req.pipe(res);       

   }).listen(9002);