#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
.