Все основные браузеры теперь поддерживают API DecompressionStream, но я не могу понять, как использовать его с fetch() для распаковки gzip-файла в браузере.
Следующий код работает со строкой base64:
const decompress = async (url) => {
const ds = new DecompressionStream('gzip');
const response = await fetch(url);
const blob_in = await response.blob();
const stream_in = blob_in.stream().pipeThrough(ds);
const blob_out = await new Response(stream_in).blob();
return await blob_out.text();
};
decompress(
'data:application/octet-stream;base64,H4sIAAAAAAAAE/NIzcnJVyjPL8pJAQBSntaLCwAAAA=='
).then((result) => {
console.info(result);
});Однако, если я создам файл hello.txt.gz, используя gzip hello.txt в MacOS (hello.txt — это обычный текстовый файл с содержимым «hello world»), то функция выше выдает ошибку.
decompress('/hello.txt.gz').then((result) => {
console.info(result);
});
# FireFox
Failed to read data from the ReadableStream: “TypeError: The input data is corrupted: incorrect header check”.
Uncaught (in promise) DOMException: The operation was aborted.
# Chrome
Uncaught (in promise) TypeError: Failed to fetch
# Safari
[Error] Unhandled Promise Rejection: TypeError: TypeError: Failed to Decode Data.
[Error] Unhandled Promise Rejection: TypeError: Failed to Decode Data.
Редактировать
На Stackblitz есть воспроизводимая демоверсия.
Это действительно похоже на то, что вы просто нажимаете 404 или что-то подобное. Проверьте свой путь и вкладку сети. Кроме того, из такого URL-адреса вам не нужно переходить к BLOB-объекту, а затем извлекать из него поток, или создавать BLOB-объект из ответа, чтобы затем получить из него текст, вы можете напрямую сделать const stream_in = response.body.pipeThrough(ds); return new Response(stream_in).text()jsfiddle. нетто/yv5wzsrt
Спасибо! @BagusTesa Я добавил демо на stackblitz.com/edit/vitejs-vite-vrvd2k?file=src%2Fmain.ts. Ответ на выборку равен 200.
Привет, @Kaiido, я добавил демо на stackblitz.com/edit/vitejs-vite-vrvd2k?file=src%2Fmain.ts. Кажется, ответ на выборку в порядке (200). Большое спасибо за ваш пример! Это сработало с моим hello.txt.gz файлом! Я буду продолжать изучать это.
О, это интересно, но нет, ответ не в порядке. Сервер отправляет Content-Type как "text/plain" и Content Encoding как "gzip" и не передает никаких данных. Каким-то образом расширение .gz заставляет его споткнуться, думая, что это один из его собственных ответов или что-то в этом роде. Измените расширение вашего файла, например. на .bin и он будет работать нормально. Я действительно не уверен, почему сервер ведет себя так, и я не уверен, является ли это только проблемой stackblitz или это конфигурация по умолчанию. Только что попробовал на моем локальном хосте (почти голая конфигурация apache), и он отлично работает, так что это будет проблема со стеком.
Вау, понятно, большое спасибо, @Kaiido!! ❤️❤️ Мне помогло изменение на .bin. Я предполагаю, что с сервером Vite происходит что-то странное. Возможно, они предварительно обрабатывают файлы с расширением .gz...
@Kaiido Не могли бы вы добавить краткий ответ, чтобы я мог принять его и закрыть проблему? 🙏
Связанная проблема с Vite: github.com/vitejs/vite/issues/12266
О, извините, у меня сейчас нет времени, чтобы составить ответ, и обнаруженная вами проблема с GH могла бы стать гораздо лучшим ответом, чем то, что я мог бы написать, так что не стесняйтесь отвечать себе :-) (Ps : я задним числом добавил проблему с vite для возможности обнаружения, поскольку на самом деле это источник проблемы).



![Безумие обратных вызовов в javascript [JS]](https://i.imgur.com/WsjO6zJb.png)


Благодаря помощи @kaiido (см. комментарии к вопросу) мы обнаружили, что эта ошибка вызвана сервером Vite. Сервер разработки обслуживает .gz файлы с неправильными заголовками.
"content-encoding": "gzip"
"content-length": "42"
"content-type": "text/plain"
Обходной путь — переименовать файл, чтобы использовать другое расширение (например, hello.txt.gz → hello.txt.gzip).
«Не удалось получить» — доступен ли файл в первую очередь?