如何从Node JS发送分块的gzip响应到浏览器

时间:2019-12-13 20:21:47

标签: node.js express http browser gzip

我正在尝试以特定的间隔发送空格,以避免heroku超时(30s),但是我想支持gzip编码。所以我正在尝试类似以下的内容:

const express = require('express')
const zlib = require('zlib')

const app = express()
const gzipped_space = zlib.gzipSync(' ');

app.get('/json-chunked', function (req, res) {
  let interval = setInterval(() => {
    res.write(' ');
  }, 1000);

  setTimeout(() => {
    res.write('{"hello":"world"}');
    clearInterval(interval);
    res.end();
  }, 5500);
});

app.get('/gzip-chunked', function (req, res) {
  res.writeHead(200, {
    'Content-Encoding': 'gzip'      // setting the encoding to gzip
  });
  let interval = setInterval(() => {
    res.write(gzipped_space);
  }, 1000);

  setTimeout(() => {
    res.write(zlib.gzipSync('{"hello":"world"}'));
    clearInterval(interval);
    res.end();
  }, 5500);
});

app.listen(3000, () => {
  console.log('listening on 3000');
})

http://localhost:3000/json-chunked在浏览器中可以正常工作,并且会收到整个json响应,并在开头添加空格。但是对于http://localhost:3000/gzip-chunked,浏览器似乎只接收第一个空格,并且请求被终止。但是,来自postman的相同请求可以正常工作,并且在那里接收并解码了整个响应。

浏览器是否希望整个响应是一个gzip主体,分为多个块,而不是较小的gzip压缩块?(浏览器不支持单独的gzip压缩块,这很奇怪:()我还有其他选择吗?可以发回空白空间以保持连接畅通吗?

编辑: gzip中是否有任何特殊字符在解压缩时会被忽略?

1 个答案:

答案 0 :(得分:0)

这是一种实现方法:

const zlib = require('zlib');
const express = require('express');

const app = express();

app.get('/gzip-chunked', function (req, res) {
  res.writeHead(200, {
    'Content-Encoding': 'gzip',      // setting the encoding to gzip
  });

  // Create a Gzip Transform Stream
  const gzip = zlib.createGzip();

  const interval = setInterval(() => {
    // Write a space character to the stream
    gzip.write(' ');

    // From Node.js docs: Calling .flush() on a compression stream will
    // make zlib return as much output as currently possible.
    gzip.flush();
  }, 1000);

  setTimeout(() => {
    gzip.write('{"hello":"world"}');
    clearInterval(interval);
    gzip.end();
  }, 5500);

  // Pipe the Gzip Transform Stream into the Response stream
  gzip.pipe(res);
});

app.listen(3000, () => {
  console.log('listening on 3000');
});