All major browsers now support the DecompressionStream API, but I can't figure out how to use it with fetch()
to decompress a gzip file in browser.
The following code works with a base64 string:
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.log(result);
});
However, if I create a hello.txt.gz
file using gzip hello.txt
on MacOS (hello.txt
is a plain text file with content "hello world"), then the function above throws an Error.
decompress('/hello.txt.gz').then((result) => {
console.log(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.
Edit
There is a reproducible demo at Stackblitz.
Thanks to @kaiido's help (see question comments), we found that this error is caused by the Vite server. The development server serve .gz
files with wrong headers.
"content-encoding": "gzip"
"content-length": "42"
"content-type": "text/plain"
A workaround is to rename the file to use a different extension (e.g., hello.txt.gz
→ hello.txt.gzip
).