経緯としては、
- CFWで作ったとあるAPIのレスポンスヘッダを眺めてた
- `content-encoding: br`になってたのを見つけた
- コードの中では特に何もしてない
- WorkerのDocsにも特にそれらしい記載はなかった
- そういえばこれってどこで圧縮してんの?
って思ったのがきっかけ。
Cloudflareが自動で圧縮する
https://support.cloudflare.com/hc/en-us/articles/200168396-What-will-Cloudflare-compress
Workerから返すレスポンスの`content-type`ヘッダが、このページにリストされてるものだった場合、それは自動的に`gzip`と`brotli`して返してくれるとのこと。
そしてこれはどうやらWorkerより外側のレイヤーで行われるらしく、Workerのコードとしては適切な`content-type`を設定するほかやることはない。
ちなみに、あまりに小さいレスポンスは無圧縮になってた。
もちろん、リクエストする側として`accept-encoding`に`gzip`か`br`があることが前提。`deflate`だけとか未指定とかだとそのまま落ちてくる。(モダンなブラウザならそんな心配はないけど)
というわけで、レスポンスの圧縮はWorkerではなくその外側でやってくれる。なので、Workerからあえて`content-encoding`を指定して返す理由はない、と。
そもそも、Workerのコードで`headers.get("accept-encoding")`しても、`gzip`しか返ってこない・・。
Cloudflare Workers lies about request Accept-Encoding - Workers - Cloudflare Community
ただし、20xの場合のみ
どうやら40xとか50xをWorkerから返したときは、`content-type`の設定だけでは圧縮してくれない風だった。
このフォーラムによると、`content-type`に加えて`cotnent-encoding`を自分で指定すれば、20xじゃないレスポンスでも圧縮してくれるらしい。
ただ手元でやってみたところ、
- Workerのレスポンスで`content-encoding: gzip`を設定すると
- Workerのレスポンスで`content-encoding: br`を設定しても
- どうリクエストしても圧縮してないものが返る
というよくわからない挙動だった。つまりブラウザ向けには、20xじゃないレスポンスの場合、自動で圧縮したレスポンスは返せないということ・・?指定しなくていいんじゃなかったの・・?
自分で圧縮してた場合はどうする
自動で圧縮してくれるがゆえに、たとえばKVなんかから自分たちで既に圧縮してあるものを返したい場合、二重で圧縮されてしまうという問題があるらしい。
さっきの`content-type`のリストのページによると、
If you do not want a particular response from your origin to be encoded, you can disable this by setting cache-control: no-transform at your origin web server.
とのことで、`cache-control: no-transform`をWorkerから返すことで、自動で圧縮されないようにできた。ただこのままだと`content-encoding`がレスポンスヘッダーに入らない。
じゃあどうすれば・・?ってのをひとしきり調べてみたけど、これだ!っていう答えを見つけられなかった。
中の人が回答してる最もそれらしいやつによると、`encodeBody`っていうCFW特有のプロパティを使う、と。
https://developers.cloudflare.com/workers/runtime-apis/response/#properties
デフォルトの`auto`から`manual`にしつつ、`content-encoding`も指定するといいらしい。
const resp = new Response(/* ... */, { headers: { "content-encoding": "gzip" }, encodeBody: "manual", // コレ });
ただこれができるのは、独自`gzip`の場合のみで、独自`brotli`はできないとのこと。
Storing Compressed Data for Cloudflare Workers Sites - Workers - Cloudflare Community
How to serve directly my Brotli and Gzip pre-compressed css and js instead of the Cloudflare compressed ones? - Workers - Cloudflare Community
わからない
Cloudflare Workersだからといって、ブラウザと直でやり取りしてるわけではないってことはわかった。
ただそのレイヤー境界で起きてることはよくわからなかった。誰か正解を教えてください・・。