Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Compressing response breaking error page #27269

Open
b-mounir-dev opened this issue May 18, 2024 · 2 comments
Open

Compressing response breaking error page #27269

b-mounir-dev opened this issue May 18, 2024 · 2 comments

Comments

@b-mounir-dev
Copy link

Environment

Working directory: /home/projects/nuxt-starter-xkjsve 1:20:34 PM
Nuxt project info: 1:20:34 PM


  • Operating System: Linux
  • Node Version: v18.18.0
  • Nuxt Version: 3.11.2
  • CLI Version: 3.11.1
  • Nitro Version: 2.9.6
  • Package Manager: npm@10.2.3
  • Builder: -
  • User Config: devtools
  • Runtime Modules: -
  • Build Modules: -

👉 Report an issue: https://github.com/nuxt/nuxt/issues/new 1:20:34 PM

👉 Suggest an improvement: https://github.com/nuxt/nuxt/discussions/new

👉 Read documentation: https://nuxt.com

Reproduction

https://stackblitz.com/edit/nuxt-starter-xkjsve

Describe the bug

I use code below to compress response before output using brotlli/gzip/deflate method, it's working good when response 200, but for 404/500 error pages this code doesn't work in async page:

import { Readable, pipeline } from 'node:stream';
import zlib from 'node:zlib';

export default defineNitroPlugin((nitroApp) => {
  nitroApp.hooks.hook('beforeResponse', async (event, response) => {
    compressResponse(event, response);
  });
});

async function compressResponse(event: any, response: { body?: unknown }) {
  if (typeof response.body !== 'string') {
    return;
  }

  // using deflate as fallback here bcz stackblitz doesn't include it in req headers
  // You can test locally without setting fallback
  const acceptableEncoding =
    getRequestHeader(event, 'accept-encoding') ?? 'deflate';

  if (
    !acceptableEncoding ||
    !/\b(deflate|gzip|br)\b/.test(acceptableEncoding)
  ) {
    return;
  }

  const originalBody = response.body;
  const stream = Readable.from(response.body);

  if (/\bbr\b/.test(acceptableEncoding)) {
    setResponseHeader(event, 'Content-Encoding', 'br');
    response.body = pipeline(
      stream,
      zlib.createBrotliCompress(),
      event.node.res,
      () => (response.body = originalBody)
    );
  } else if (/\bgzip\b/.test(acceptableEncoding)) {
    setResponseHeader(event, 'Content-Encoding', 'gzip');
    response.body = pipeline(
      stream,
      zlib.createGzip(),
      event.node.res,
      () => (response.body = originalBody)
    );
  } else {
    setResponseHeader(event, 'Content-Encoding', 'deflate');
    response.body = pipeline(
      stream,
      zlib.createDeflate(),
      event.node.res,
      () => (response.body = originalBody)
    );
  }
}

Additional context

No response

Logs

No response

Copy link

stackblitz bot commented May 18, 2024

Fix this issue in StackBlitz Codeflow Start a new pull request in StackBlitz Codeflow.

@aaharu
Copy link
Contributor

aaharu commented May 23, 2024

Since /__nuxt_error is broken trying to compress, adding the following to compressResponse may work.

    if (getRequestURL(event).pathname.startsWith('/__nuxt')) {
      return
    }

However, it may be recommended to do this with a proxy rather than compressing with the nitro plugin.
unjs/nitro#1007 (comment)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

3 participants