How can I output data before I end the response?

半城伤御伤魂 提交于 2019-11-27 08:37:37

If you change the content type to text/plain -- e.g:

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

then firefox will show the content immediately. Chrome still seems to buffer (if you write a bunch more content, chrome will show it immediately).

There actually is a way that you can do this without setting Content-Type: text/plain and still use text/html as the Content-Type, but you need to tell the browser to expect chunks of data.

This can be done easily like this:

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);


You should be aware though, that until response.end() is called the request is still taking place and blocking other requests to your nodejs server.
You can easily test this by opening calling this page (localhost:8888) on two different tabs. One of them will wait 10 seconds, and the other will only get the beginning of the response once the first response ends (meaning you'll wait 10 seconds for the beginning of the response and another 10 seconds till the end of the response, using this code).

You can probably pass this obstacle too by running a couple of nodejs processes and load balancing between them, but then this begins to get much more complicated, and is a thread that should be taken else where... :)

Vlad

If you want to output chunked plain text in Chrome - just like what Firefox is doing by default - you need to use the 'X-Content-Type-Options': 'nosniff' header. See 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('Beginning\n');
    var count = 10;
    var io = setInterval(function() {
        res.write('Doing ' + count.toString() + '\n');
        count--;
        if (count === 0) {
            res.end('Finished\n');
            clearInterval(io);
        }
    }, 1000);
}).listen(8888);

You don't need this option if your output is text/html.

Solution found from this Chrome defect: Transfer-Encoding chunked not support on text/plain

Here are the primary points you need to take note of:

  • specify a charset
  • each "chunk" will be outputted by the browser (atleast, what I noticed in Chrome) through a new line (<br> if the charset is text/html)

Like so:

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);
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!