compress icon indicating copy to clipboard operation
compress copied to clipboard

Expand documentation

Open slanden opened this issue 4 years ago • 12 comments

This middleware looks useful, but I'm not sure how to use it. Perhaps more examples with explanations would help?

I'd like to use brotli if the client accepts it, and fallback to gzip if not. In the readme, your example disables brotli and later states,

Brotli compression is supported in node v11.7.0+, which includes it natively.

Is brotli disabled because Node includes it natively or because that's just the example?

The current encodings are, in order of preference: br, gzip, deflate

Does the order of the encodings in the options object matter or is the "preference" always the same order?

Does one encoding fallback to another if not supported?

I'm unable to help with contributing these changes because I don't understand how it works, but I think answering these questions in the readme would help others understand. Or maybe it's just me..

slanden avatar Jun 23 '20 02:06 slanden

PR welcome!

niftylettuce avatar Jul 04 '20 18:07 niftylettuce

The user/client is the one that ultimately determines what compression methods it accepts.

niftylettuce avatar Jul 04 '20 18:07 niftylettuce

Is brotli disabled because Node includes it natively or because that's just the example?

It is just an example. If you don't do anything, clients supporting br will get a br response, if your server is running on v11.7.0+.

Does one encoding fallback to another if not supported?

If a client or a server doesn't support an encoding from the list, the next one will be checked and used.

Does this explanation work for you? If not, ask away and let's refine our message. If it does, I'll be happy to submit a PR to update the docs.

uhop avatar Jul 07 '20 04:07 uhop

@uhop Thank you, yes I think your answers make sense. It'd be helpful as well to be clear about what will happen by default (whether Node 11.7+ or an unsupported version), and then the order the fallbacks will happen.

So, here's my understanding based on what you've said:

app.use(compress())

will result in responses using brotli compression if using Node 11.7+, and otherwise return gzip responses. If for some reason gzip doesn't work or is not an option (again, I don't know anything about compression), then deflate is used.

This is always the order of selection. If an Options object is passed, the order of its keys doesn't change this order.

Is that correct?

Also, for options.defaultEncoding

An optional string, which specifies what encoders to use for requests without Accept-Encoding

does this mean that in all cases, Koa Compress checks the request's Accept-Encoding header to further eliminate compression options from the selection?

It seems natural that this would be the case, but I'm not one for assumptions..

options.defaultEncoding is also stated to be set to identity by default. What does that do?

slanden avatar Jul 08 '20 02:07 slanden

So, here's my understanding based on what you've said

Encoders are going to be tried in this order: ['br', 'gzip', 'deflate'] unless eliminated by Accept-Encoding and availability of actual encoders (brotli).

Also, for options.defaultEncoding

When a client sends Accept-Encoding, its value is a list/set of accepted encodings. The rest is trivial. But there are two edge cases:

  1. The client does not send Accept-Encoding at all.
  2. The client sends Accept-Encoding set to "*".

In the former case, options.defaultEncoding is used. By default, it is identity. By the standard, it should be "*", which gets many people with curl or wget puzzled.

In the latter case, it will be ['gzip', 'deflate'].

What if all encoders are somehow eliminated? The catch-all will be identity.

options.defaultEncoding is also stated to be set to identity by default. What does that do?

identity means "no compression". Data will be left unchanged and no encoding is going to be used.


options.defaultEncoding is documented. Two other arrays (the order of encoders and the "*" substitute) are not, but they are available to be replaced by a user. Probably they should be documented, and even made available through options.

uhop avatar Jul 08 '20 03:07 uhop

In the latter case, it will be ['gzip', 'deflate'].

Why is 'br' not listed here also?

slanden avatar Jul 09 '20 21:07 slanden

Beats me. TBH using "*" doesn't make much sense at all. What does it mean? All possible encodings, including uninvented yet? I never saw it being used in the wild. I suspect that if some client uses it, it is probably a legacy one, which doesn't know about brotli. That's probably why.

IMHO the only plausible scenario for "*" is a closed system. For example, I have a client, which talks only to a certain server. The server can use only a set of predefined encodings. My client may understand all of them and indicate it with "*". In this scenario, the set of supported encodings on both sides is implicitly defined and cannot change.

uhop avatar Jul 09 '20 22:07 uhop

I think you've cleared up everything that was missing from the docs, thank you! I don't understand the relation between our last two comments, but

Beats me.

tells me you didn't leave out the 'br' from that list by accident so that's good enough for me.

slanden avatar Jul 12 '20 17:07 slanden

Beats me.

I guess that the authors decided to be reasonably conservative and in the case of "*" they will serve gzip. I don't see any other possible scenario when any other encoding is going to be selected. br is not included to prevent it from being selected instead of gzip.

uhop avatar Jul 13 '20 05:07 uhop

https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Accept-Encoding we are just trying to be as true to the specs as possible :) it's very confusing

jonathanong avatar Aug 21 '21 01:08 jonathanong

Hello there! Catching up with this thread. Have a question for a simple general use case using Koa for an API for a website. Can just use compress() without any customizations? It seems to work fine. As a library user, I'd like to trust the defaults.

In examples around the internet, I've seen gzip: { flush: require('zlib').constants.Z_SYNC_FLUSH } passed very frequently. What does this do, and is it required to explicitly pass?

Thanks to all for contributing and maintaining koa-compress!

guillermodlpa avatar Feb 21 '23 10:02 guillermodlpa

Here's what we do for @forwardemail and @ladjs:

      // https://github.com/koajs/compress
      app.use(compress({
        br: {
          params: {
            [zlib.constants.BROTLI_PARAM_MODE]: zlib.constants.BROTLI_MODE_TEXT,
            [zlib.constants.BROTLI_PARAM_QUALITY]: 4
          }
        }
      }));

titanism avatar Feb 21 '23 18:02 titanism