Reputation: 7628
I am working on a Vue application with a Laravel back-end API. After clicking on a link I would like to do a call to the server to download a certain file (most of the time a PDF file). When I do a get
request with axios
I get a PDF in return, in the body of the response. I would like to download that file directly.
To give you a better view of how the response is looking like:
(note: I know a real text response is better than an image but I don't see any way to return that because of the length of the actual PDF content..)
Is there any way of downloading that file with JavaScript or something? It has to be specific a direct download without clicking on the button again.
Code
// This method gets called when clicking on a link
downloadFile(id) {
const specificationId = this.$route.params.specificationId;
axios
.get(`${this.$API_URL}/api/v1/suppliersmanagement/product-specifications/${specificationId}/fileupload/${id}/download`, {
headers: this.headers,
})
.then(response => {
console.log(response);
// Direct download the file here..
})
.catch(error => console.log(error));
},
Upvotes: 41
Views: 101901
Reputation: 59
I encountered same issue, and this is how I solved it.
Below is how i download the pdf through NodeJs and Axios:
const url = `https://www.buds.com.ua/images/Lorem_ipsum.pdf`;
return await axios.get(url, { responseType: 'stream' });
If you want to forward the .pdf content through your own api you will have to send it as stream of data Below is implementation for it:
response.data.pipe(res);
Hence complete code for your API would be:
async function forwardPDF(req, res) {
try {
// Fetch the PDF from the URL
const url = `https://www.buds.com.ua/images/Lorem_ipsum.pdf`;
const response = await axios.get(url, { responseType: 'stream' });
// Pipe the PDF to the response
response.data.pipe(res);
} catch (error) {
const header = Header(true, error.statusCode, error.message, error.stack);
res.send(Response(header, {}));
}
}
Upvotes: 0
Reputation: 21
const downloadPDF = (id, fileName) => {
axios({
method: 'get',
url: `https://api.example.com/pdf/invoice/${id}`,
headers: {
'Authorization': 'Bearer ' + localStorage.getItem('token'),
'Content-Type': 'application/json'
},
responseType: 'blob'
}).then(function (response) {
const a = document.createElement('a');
a.href = window.URL.createObjectURL(response.data);
a.download = `${fileName}.pdf`;
document.body.appendChild(a);
a.click();
a.remove();
});
}
Upvotes: 2
Reputation: 123148
The key is using responseType: 'stream'
per the Axios docs.
import axios from 'axios';
import { writeFile } from 'fs/promises';
const downloadFile = async () => {
const response = await axios.get('https://someurl', {
params: {
// ...
},
// See https://axios-http.com/docs/api_intro
responseType: 'stream',
});
const pdfContents = response.data;
await writeFile('file.pdf', pdfContents);
};
Upvotes: 6
Reputation: 1997
You should use 'responseType' option. For example:
axios.get(
url,
{responseType: 'blob'} // !!!
).then((response) => {
window.open(URL.createObjectURL(response.data));
})
Upvotes: 32
Reputation: 2459
You have 2 options for this. If you want to do it from server and if you are using Node.js as a backend. You can do it easily using res.download
method of express. You can follow this answer for that Download a file from NodeJS Server using Express.
But if you want to handle it from client then there are few options since you can't use axios, XHR, fetch to download file directly. You can either use download.js
or write your own code in following way.
return axios({
url: '/download', // download url
method: 'get',
headers: {
Accept: 'application/json',
'Content-Type': 'application/json',
mode: 'no-cors'
}
})
.then(response => response.blob())
.then(blob => {
var url = window.URL.createObjectURL(blob)
var a = document.createElement('a')
a.href = url
a.download = fileName
a.click()
a.remove()
setTimeout(() => window.URL.revokeObjectURL(url), 100)
})
Since response returned from server is in json
format you need to convert it into ObjectURL
and set it to anchor tag.
If you sneak inside download.js
code you will find same implementation.
Upvotes: 10
Reputation: 357
You can do it like this
download(filename) {
fetch(url , { headers })
.then(response => response.blob())
.then(blob => URL.createObjectURL(blob))
.then(uril => {
var link = document.createElement("a");
link.href = uril;
link.download = filename + ".csv";
document.body.appendChild(link);
link.click();
document.body.removeChild(link);
});
}
here I want to download a CSV file, So I add .csv to the filename.
Upvotes: 1
Reputation: 7628
As @Sandip Nirmal suggested I've used downloadjs
and that worked out pretty good! Had to make a few adjustments to my code but in the end it worked out.
My new code
// npm i downloadjs
import download from 'downloadjs'
// method
downloadFile(file) {
const specificationId = this.$route.params.specificationId;
axios
.get(`${this.$API_URL}/api/v1/suppliersmanagement/product-specifications/${specificationId}/fileupload/${file.id}/download`, {
headers: this.headers,
responseType: 'blob', // had to add this one here
})
.then(response => {
const content = response.headers['content-type'];
download(response.data, file.file_name, content)
})
.catch(error => console.log(error));
},
Upvotes: 48