

Node.jsを用いて下記のような形で、gzip圧縮されたhtmlファイルをレスポンスとして返しています。

[code]

    const hoge = 'huga';
    res.setHeader('Content-Disposition', 'attachment; filename=test.html.gz');
    res.setHeader('Content-Encoding', 'gzip');
    res.setHeader('Content-Type', 'text/html; charset=UTF-8');
    
    zlib.gzip(hoge, (err, result) => {
      res.send(result);
    });
    
[/code]

上記処理があるエンドポイントを叩くと、`test.html.gz`がダウンロードできるのですが、  
gzip解凍時エラーが出ます。

直接ファイル名を編集し、`test/html`とするとhtmlファイルとして開くことができるため、gzipに圧縮できていないものと考えています。  
正常にgzip圧縮を行い、レスポンスするにはどのようにすれば良いでしょうか。


CC BY-SA 4.0
2021-09-15T11:31:47.430
82508
2021-09-16T10:48:21.767
48223
question
javascript node.js gzip
NodeJSでzlibを使用しレスポンスしたgzipが圧縮されていない


express.jsでレスポンスをgzip化するのであれば、`compression`を利用するのが（ドキュメントにも書いてあるので）一般的かと思います。

  * <https://expressjs.com/ja/advanced/best-practice-performance.html>
  * <https://github.com/expressjs/compression>

以下がサンプルコードです。`http://localhost:3000`にアクセスしてDevToolsで確認してみてください。

`server.js`などのように保存して、`node
server.js`として実行してみてください。レスポンスに乗せるContentがあまりにも小さい場合、gzip化されないので気をつけてください。サンプルコードではわざとfor-
loopを回しています。

[code]

    const expres = require("express");
    const compression = require("compression");
    
    const app = expres();
    
    app.use(compression({
      threshold: 0,
    }));
    
    const domText = [];
    
    for (let i = 0; i < 10; i++) {
      domText.push(`<li>Random Number ${Math.random()}</li>`);
    }
    
    const htmlText = `<!DOCTYPE html>
    <html lang="en">
    <head>
      <meta charset="UTF-8">
      <meta http-equiv="X-UA-Compatible" content="IE=edge">
      <meta name="viewport" content="width=device-width, initial-scale=1.0">
      <title>Hello world page</title>
    </head>
    <body>
      <h1>Hello world from express.js</h1>
      <ul>
      ${domText.join("\n")}
      </ul>
    </body>
    </html>
    `;
    
    app.get("/", (req, res) => {
      res.send(htmlText);
      res.end();
    });
    
    app.listen(3000, () => {
      console.log("Start server: http://localhost:3000");
    });
    
[/code]

[![DevToolsでの確認](https://i.stack.imgur.com/C93Pp.jpg)](https://i.stack.imgur.com/C93Pp.jpg)

## 興味ある人向け

質問の趣旨から外れるかもしれませんが、ライブラリを使わずに記述するパターンは以下のようになります。

[code]

    const http = require("http");
    const zlib = require("zlib");
    
    const availableGzip = (header) => {
      return typeof header === "string" && Boolean(header && /gzip/i.test(header));
    };
    
    const htmlText = `<!DOCTYPE html>
    <html lang="en">
    <head>
      <meta charset="UTF-8">
      <meta http-equiv="X-UA-Compatible" content="IE=edge">
      <meta name="viewport" content="width=device-width, initial-scale=1.0">
      <title>Hello world page</title>
    </head>
    <body>
      <h1>Hello world</h1>
    </body>
    </html>
    `;
    
    const rootRouter = (req, res) => {
      const message = htmlText;
      if (availableGzip(req.headers["accept-encoding"])) {
        zlib.gzip(Buffer.from(message), (err, data) => {
          res.setHeader("Content-Encoding", "gzip");
          res.setHeader("Content-Length", data.byteLength);
          res.setHeader("Content-Type", "text/html; charset=UTF-8");
          res.writeHead(200);
          res.end(data);
        });
      } else {
        res.setHeader("Content-Length", message.length);
        res.writeHead(200);
        res.end(message);
      }
    };
    
    const notFoundRouter = (req, res) => {
      res.write("Not found page");
      res.end();
    };
    
    const requestListener = (req, res) => {
      switch (req.url) {
        case "/":
          rootRouter(req, res);
          break;
        default:
          notFoundRouter(req, res);
          break;
      }
    };
    
    const server = http.createServer(requestListener);
    
    server.listen(3000);
    
    console.log("Server start: http://localhost:3000");
    
[/code]

参考:
[テキストリソースを圧縮してウェブサイトのパフォーマンスを改善する](https://numb86-tech.hatenablog.com/entry/2020/10/25/193353)にもう少し詳しい情報が乗っています。


CC BY-SA 4.0
2021-09-16T10:48:21.767
82537
2021-09-16T10:48:21.767
7997
82508
answer