I have some very simple Node.js code that I want to emit as chunked responses. The code is:
const WAIT = 500;
const records = [...];
function getList(req, res, url) {
var list = records.slice().map(rec => JSON.stringify(rec) + "\n");
var len = list.reduce((size, cur) => { size += Buffer.byteLength(cur); return size; }, 0);
function next() {
var cur = list.shift();
if(!cur) {
res.end();
return;
}
res.write(cur);
setTimeout(next, WAIT);
}
res.writeHead(200, {
"Access-Control-Allow-Origin": "*",
"Content-Type": "application/x-ndjson",
"Content-Length": len.toString(),
"X-Accel-Buffering": "no"
});
setTimeout(next, WAIT);
}
const PORT = process.env.PORT || 8080;
require("http").createServer(getList).listen(PORT);
This should write out this data as ndjson chunks until the array is emptied.
Locally and in a generic VPS this works as expected. On Heroku it does not emit the chunks in a streaming fashion, but rather dumps out them all at the end.
Does anyone have an idea of what I might be doing wrong?
After the comments section - setting the
Transfer-Encoding: Chunked
header explicitly resolved this problem. Digital Ocean might be doing something smart with chunking while you need to specify this explicitly in Heroku.Documentation regarding the header: https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Transfer-Encoding
Another potential problem why this might occur in your system: https://github.com/expressjs/compression/issues/56 (If you're using an older version of expressjs - response flushing contained a bug)