如何在结束响应之前输出数据



这是我在Chrome 11和Firefox 4:中测试的片段

var http = require('http');
http.createServer(function(request, response){
   // Write Headers
   response.writeHead(200);
   // Write Hello World!
   response.write("Hello World!");
   // End Response after 5 seconds
   setTimeout(function(){ 
        response.end(); 
   }, 5000);
}).listen(8000);

如您所见,我使response.end()超时,因此我可以测试response.write是否在response.end之前输出。但根据我的经验,情况并非如此。

有没有一种方法可以在结束响应之前输出数据,比如以数据包的形式发送数据?

实际上有一种方法可以在不设置Content-Type: text/plain的情况下做到这一点,并且仍然使用text/html作为Content-Type,但您需要告诉浏览器需要数据块。

这可以像这样简单地完成:

var http = require('http');
http.createServer(function(request, response) {
    response.setHeader('Connection', 'Transfer-Encoding');
    response.setHeader('Content-Type', 'text/html; charset=utf-8');
    response.setHeader('Transfer-Encoding', 'chunked');
    response.write('hello');
    setTimeout(function() {
        response.write(' world!');
        response.end();
    }, 10000);
}).listen(8888);


不过,您应该知道,在调用response.end()之前,请求仍在进行,并阻止其他对nodejs服务器的请求
您可以通过在两个不同的选项卡上打开调用此页面(localhost:8888)来轻松测试这一点。其中一个将等待10秒,另一个只有在第一个响应结束后才会得到响应的开始(这意味着使用此代码,您将等待10秒钟等待响应的开始,再等待10秒钟直到响应结束)。

您可能也可以通过运行几个nodejs进程并在它们之间进行负载平衡来克服这个障碍,但随后这开始变得更加复杂,并且是一个应该在其他地方使用的线程…:)

如果将内容类型更改为text/plain,例如:

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

那么firefox将立即显示内容。Chrome似乎仍然可以缓冲(如果你写了更多的内容,Chrome会立即显示)。

如果您想在Chrome中输出分块的纯文本,就像Firefox默认情况下所做的那样,您需要使用'X-Content-Type-Options': 'nosniff'标头。请参阅"What is";X-Content-Type-Options=nosniff";?

var http = require('http');
http.createServer(function (req, res) {
    res.writeHead(200, {
        'Content-Type': 'text/plain; charset=utf-8',
        'Transfer-Encoding': 'chunked',
        'X-Content-Type-Options': 'nosniff'});
    res.write('Beginningn');
    var count = 10;
    var io = setInterval(function() {
        res.write('Doing ' + count.toString() + 'n');
        count--;
        if (count === 0) {
            res.end('Finishedn');
            clearInterval(io);
        }
    }, 1000);
}).listen(8888);

如果您的输出是text/html,则不需要此选项。

从这个Chrome缺陷中找到的解决方案:文本/纯不支持传输编码块

以下是您需要注意的要点:

  • 指定一个字符集
  • 每个"chunk"将由浏览器(至少,我在Chrome中注意到的)通过一行新行(如果字符集是text/html,则为<br>)输出

像这样:

res.setHeader('Content-Type', 'text/html; charset=utf-8');
res.write('a<br>');
setTimeout(function() {
  res.write('b<br>');
  setTimeout(function() {
    res.write('c');
    res.end();
  }, 2000);
}, 2000);

最新更新