3

I am sending a zip file from my nodejs server to the browser using the following

res.set("Content-Type", "application/octet-stream");
res.set("Content-disposition", `attachment; filename="`+zip_name+`.zip"`);
res.set("Content-Length", zipBuff.length);
res.send(zipBuff);

I am then fetching it by using :

fetch("/my/url", {
    method: "POST",
    body: formData,
})
    .then(response => {
        return response.blob();
    })
    .then(response => {
        const blob = new Blob([response], {type: 'application/zip'});
        const downloadUrl = URL.createObjectURL(blob);
        const a = document.createElement("a");
        a.href = downloadUrl;
        a.download = "blah.zip";
        document.body.appendChild(a);
        a.click();
    });

I would like to be able to use zip_name instead of blah for the filename but I can't figure out how to access the headers (in that case Content-disposition) of the response with fetch.

Could someone please explain how it's done ?

Chapo
  • 2,563
  • 3
  • 30
  • 60

2 Answers2

4

Return blob and headers in object

fetch("/my/url", {
    method: "POST",
    body: formData,
})
    .then(response => {
        const headers = response.headers
        return { blob: response.blob(), headers }
    })
    .then(({blob, headers}) => {
        /// now you can access to **headers** and blob data
    });

UPD:

To access the headers use headers.get("Header name").split('=').pop()

UPD1:

const foo = async () => {
    const response = await fetch("/my/url", {
        method: "POST",
        body: formData,
    })
    if(!response.ok)
        thorw new Error("Some error happend")

    const blod_data = await response.blob()
    const header_with_name = response.headers.get("Header name").split('=').pop()
    // do something with it
}
  • Thanks this is useful. Interestingly when I use this method, my zip file becomes invalid. The only thing I've changed is this specific thing (and pointing to the right place in the next bit of code of course). Any ideas ? – Chapo Feb 08 '21 at 15:53
  • in fact you should take into account the fact that response.blob() is itself a promise. the above won't work. – Chapo Feb 09 '21 at 06:50
  • https://stackoverflow.com/questions/66105336/accessing-headers-during-fetch-api-call-renders-file-data-unusable – Chapo Feb 09 '21 at 06:50
  • then try async await functions – Levaya Pochta Feb 09 '21 at 16:49
2

In the first promise arrow function you have access to the HTTP response headers. If you update it to return the promise from the blob function call. Then in this nested function you can return an object that includes the header value to the outer second arrow function that processes the blob data.

Updated fetch example that includes processing the Promise returned from blob-function call.

fetch("/my/url", {
    method: "POST",
    body: formData,
})
    .then(response => {
       return response.blob().then((data) => {
          return {
            data: data,
            filename: response.headers.get('Content-disposition'),
          };
       });
    })
    .then(({ data, filename }) => {
        const blob = new Blob([data], { type: 'application/zip' });
        const downloadUrl = URL.createObjectURL(blob);
        const a = document.createElement("a");
        a.href = downloadUrl;
        a.download = filename.split('=')[1];
        document.body.appendChild(a);
        a.click();
    });

Thank you Chapo for pointing out the issue with my previous example

  • 1
    response.blob() is itself a promise so the above won't work : https://stackoverflow.com/questions/66105336/accessing-headers-during-fetch-api-call-renders-file-data-unusable – Chapo Feb 09 '21 at 06:50