What I wanted:
- send files of any formats from the back-end to the front-end
My tools:
- axios, express, saveAs
The problem I faced with:
- Unable to download zip file using axios
- https://github.com/eligrey/FileSaver.js/issues/156
- https://github.com/axios/axios/issues/448
Nothing helped me, probably because I did something wrong. But here is a simple and quick solution that I came up with:
//BE
const filename = "my-file-name.json";
const zip = new AdmZip();
zip.addFile(filename, body);
const content = zip.toBuffer();
res.set({
"Content-Length": Buffer.byteLength(content), //I'm not sure if this is necessary, but it's better to let it be :-)
"Content-Type": "text/plain",
"Content-Disposition": `attachment; filename=${filename}.${format}`,
});
res.status(200).send(content.toString("hex")); //my solution to the problem
//FE
const { headers, data } = await axios.post(myEndpoint);
const headerLine = headers["content-disposition"];
const filename = headerLine.replace(/[\w; ]+filename=/g, "");
const content = Buffer.from(data, "hex");
const blob = new Blob([content], { type: "application/zip" });
saveAs(blob, filename); //file-saver npm package
Answer from pi88a on Stack OverflowWhat I wanted:
- send files of any formats from the back-end to the front-end
My tools:
- axios, express, saveAs
The problem I faced with:
- Unable to download zip file using axios
- https://github.com/eligrey/FileSaver.js/issues/156
- https://github.com/axios/axios/issues/448
Nothing helped me, probably because I did something wrong. But here is a simple and quick solution that I came up with:
//BE
const filename = "my-file-name.json";
const zip = new AdmZip();
zip.addFile(filename, body);
const content = zip.toBuffer();
res.set({
"Content-Length": Buffer.byteLength(content), //I'm not sure if this is necessary, but it's better to let it be :-)
"Content-Type": "text/plain",
"Content-Disposition": `attachment; filename=${filename}.${format}`,
});
res.status(200).send(content.toString("hex")); //my solution to the problem
//FE
const { headers, data } = await axios.post(myEndpoint);
const headerLine = headers["content-disposition"];
const filename = headerLine.replace(/[\w; ]+filename=/g, "");
const content = Buffer.from(data, "hex");
const blob = new Blob([content], { type: "application/zip" });
saveAs(blob, filename); //file-saver npm package
Your problem is that you didn't explicitly specify the response type in your PUT request. This should work:
const exportCards = () => {
axios
.put(url, {
ids: ids,
}, {
responseType: 'blob'
})
.then((res) => { // Now 'res.data' is Blob, not a string
var file = window.URL.createObjectURL(res.data);
window.location.assign(file);
})
.catch((e) => console.log(e));
};

reactjs - Download zip files using axios - Stack Overflow
How to download files using axios - Stack Overflow
node.js - Unable to download zip file using axios - Stack Overflow
Zip File downloaded using ReactJs/Axios is corrupted
Videos
- Download the file with Axios as a
responseType: 'blob' - Create a file link using the blob in the response from Axios/Server
- Create
<a>HTML element with a the href linked to the file link created in step 2 & click the link - Clean up the dynamically created file link and HTML element
axios({
url: 'http://api.dev/file-download', //your url
method: 'GET',
responseType: 'blob', // important
}).then((response) => {
// create file link in browser's memory
const href = URL.createObjectURL(response.data);
// create "a" HTML element with href to file & click
const link = document.createElement('a');
link.href = href;
link.setAttribute('download', 'file.pdf'); //or any other extension
document.body.appendChild(link);
link.click();
// clean up "a" element & remove ObjectURL
document.body.removeChild(link);
URL.revokeObjectURL(href);
});
Check out the quirks at https://gist.github.com/javilobo8/097c30a233786be52070986d8cdb1743
Full credits to: https://gist.github.com/javilobo8
More documentation for URL.createObjectURL is available on MDN. It's critical to release the object with URL.revokeObjectURL to prevent a memory leak. In the function above, since we've already downloaded the file, we can immediately revoke the object.
Each time you call createObjectURL(), a new object URL is created, even if you've already created one for the same object. Each of these must be released by calling URL.revokeObjectURL() when you no longer need them.
Browsers will release object URLs automatically when the document is unloaded; however, for optimal performance and memory usage, if there are safe times when you can explicitly unload them, you should do so.
When response comes with a downloadable file, response headers will be something like:
{
"Content-Disposition": "attachment;filename=report.xls"
"Content-Type": "application/octet-stream" // or "application/vnd.ms-excel"
}
What you can do is create a separate component, which will contain a hidden iframe.
import * as React from 'react';
var MyIframe = React.createClass({
render: function() {
return (
<div style={{display: 'none'}}>
<iframe src={this.props.iframeSrc} />
</div>
);
}
});
Now, you can pass the url of the downloadable file as prop to this component. So when this component will receive prop, it will re-render and file will be downloaded.
Edit: You can also use js-file-download module. Link to Github repo
const FileDownload = require('js-file-download');
Axios({
url: 'http://localhost/downloadFile',
method: 'GET',
responseType: 'blob', // Important
}).then((response) => {
FileDownload(response.data, 'report.csv');
});
Using React/Axios. I am trying to download a zip file from a Django API. The zip file is always corrupted when I try to unzip it. When I perform the same request on Postman, everything works fine. Here is my code fragment:
axios
.post('http://0.0.0.0:8000/sheets/', data,
{
headers: {
'Content-Type': 'multipart/form-data',
'responseType': 'arraybuffer'
}
})
.then(res => {
console.log(res.data)
const disposition = res.request.getResponseHeader('Content-Disposition')
var fileName = "";
var filenameRegex = /filename[^;=\n]*=((['"]).*?\2|[^;\n]*)/;
var matches = filenameRegex.exec(disposition);
if (matches != null && matches[1]) {
fileName = matches[1].replace(/['"]/g, '');
}
let blob = new Blob([res.data], { type: 'application/zip' })
const downloadUrl = URL.createObjectURL(blob)
let a = document.createElement("a");
a.href = downloadUrl;
a.download = fileName;
document.body.appendChild(a);
a.click();Am I doing something obviously wrong?
Thanks!
To add to btbam91's reply: responseType has to be part of the config. In the above example:
axios
.post('http://0.0.0.0:8000/sheets/', data,
{
responseType: 'arraybuffer',
headers: {
'Content-Type': 'multipart/form-data',
}
})
The problem was that 'responseType': 'arraybuffer' should not be in "headers."