Доступ к сжатым данным для рабочих сайтов Cloudflare

#cloudflare #cloudflare-workers

#cloudflare #cloudflare-workers

Вопрос:

На моем сайте cloudflare workers хранятся двоичные данные, которые извлекает приложение react. Эти двоичные данные хранятся в сжатом виде в формате gzip, поскольку они очень хорошо сжимаются (мы говорим об уменьшении в 20-25 раз, а в несжатом виде они слишком велики, чтобы вписаться в ограничение в 10 МБ КВ). Проблема, с которой я сталкиваюсь, заключается в том, что либо рабочий возвращает данные без соответствующего заголовка:

 Content-Encoding: gzip
  

или, если я попрошу работника добавить заголовок, cloudflare дважды сожмет ответ. Итак, как мне сохранить сжатые данные gzip в cloudflare KV, чтобы я мог вернуть их с правильной кодировкой содержимого и без двойного сжатия ответа cloudflare?

Ссылка

Для минимального воспроизведения: вот два рабочих сценария, которые я использую.

 import { getAssetFromKV, mapRequestToAsset } from '@cloudflare/kv-asset-handler'

addEventListener('fetch', event => {
  try {
    event.respondWith(handleEvent(event))
  } catch (e) {
    event.respondWith(new Response('Internal Error', { status: 500 }))
  }
})

async function handleEvent(event) {
  const cacheControl = { browserTTL: 60 * 60 * 6 };
  return await getAssetFromKV(event, { mapRequestToAsset, cacheControl });
}
  

Приведенный выше рабочий скрипт возвращает двоичные данные без заголовка content encoding, поэтому браузер автоматически не раздувает ответ.

Затем я попытался добавить заголовок вручную через

 import { getAssetFromKV, mapRequestToAsset } from '@cloudflare/kv-asset-handler'

addEventListener('fetch', event => {
  try {
    event.respondWith(handleEvent(event))
  } catch (e) {
    event.respondWith(new Response('Internal Error', { status: 500 }))
  }
})

async function handleEvent(event) {
  const cacheControl = { browserTTL: 60 * 60 * 6 };
  const resp = await getAssetFromKV(event, { mapRequestToAsset, cacheControl });
  resp.headers.set("Content-Encoding", "gzip");
  return resp;
}
  

Ответ имеет правильную кодировку содержимого, но cloudflare сжимает ответ, поэтому теперь он обслуживает gzip внутри gzip.

Есть ли какой-либо способ найти золотую середину, где я мог бы обслуживать сжатые данные из cloudflare KV с правильным заголовком и без двойного сжатия ответа?

Комментарии:

1. Можете ли вы попробовать добавить Content-Type: application/octet-stream заголовок (в дополнение к Content-Encoding )? Это может помешать CF повторно сжать его. support.cloudflare.com/hc/en-us/articles /…

2. Хорошая идея, я попробовал, и, к сожалению, она по-прежнему сжимается вдвойне. Похоже, что добавление заголовка content encoding указывает cloudflare сжимать ответ, даже если это неподдерживаемый тип контента.

Ответ №1:

Это досадная ошибка спецификации Service Workers — она предназначена для использования в браузере, где ожидается, что тела ответов будут распакованы перед запуском worker, и не ожидается, что они будут снова переданы по сети. Чтобы обеспечить согласованность, Cloudflare Workers должен повторно сжимать данные в соответствии с content-encoding заголовком при передаче. Но это, в свою очередь, означает, что нет возможности обслуживать данные, которые уже сжаты.

Чтобы решить эту проблему, мы (Cloudflare) добавили нестандартную Response опцию с именем encodeBody , которая может быть "auto" (по умолчанию) или "manual" (предполагается, что тело уже сжато).

Таким образом, вы можете написать такой код, как этот:

 let resp = await getAssetFromKV(event, { mapRequestToAsset, cacheControl });

// Make a new response with the same body but using manual encoding.
resp = new Response(resp.body, {
  status: resp.status,
  headers: resp.headers,
  encodeBody: "manual"
});

// Modify headers and return.
resp.headers.set("Content-Encoding", "gzip");
return resp;
  

Комментарии:

1. Почему я не могу сделать то же самое, используя сжатие Brotli? Т.е. Content-Encoding: br Никогда не доходит до ответа, даже когда я устанавливаю заголовок от работника. Но gzip работает нормально…

2. @ezekg Спецификация требует такого поведения только для gzip. Возможно, мы могли бы добавить поддержку Brotli в будущем, но на данный момент мы этого не сделали.

3. @KentonVarda Как мы можем узнать, когда это делать, учитывая, что Cloudflare перезаписывает заголовок «accept-encoding», прежде чем передавать его рабочим?

4. @MERTON Вы можете найти исходное значение заголовка accept-encoding в request.cf.clientAcceptEncoding .