如何从节点 js 向浏览器发送分块 gzip 响应

How to send chunked gzip response to browser from node js

我正在尝试以特定间隔发送 spaces 以避免 heroku 超时(30 秒),但我想支持 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 works correctly in the browser and whole json response is received with spaces in the start. But for http://localhost:3000/gzip-chunked 浏览器似乎只接收到第一个 space 并且请求被终止。然而,来自 postman 的相同请求可以正常工作,并且可以在那里接收和解码整个响应。

浏览器是否期望整个响应是一个分成块的 gzip 主体而不是较小的 gzip 块?(浏览器不支持单独的 gzip 块感觉很奇怪:( )是否有任何其他选项我可以发回空 space 以保持连接?

编辑: gzip中有没有解压时忽略的特殊字符?

这里有一个方法:

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