Reputation: 3877
I am trying to send a pdf file hosted on the server to the client, to be downloaded from the browser. I am using express and node js.
The code on the server is :
app.get('/files', async (req, res) => {
res.sendFile(__dirname + '/boarding-pass.pdf');
});
The code on the client (react js) is :
const handleClick = async () => {
const response = await axios({
url: 'http://localhost:4000/files',
// url: '/static/boarding-pass.pdf',
method: 'GET',
headers: {
'Content-Type': 'application/json',
'Accept': 'application/pdf',
'Authorization': 'Basic d29vZG1hYzpXb29kbWFjOTI3IQ=='
},
responseType: 'arraybuffer',
//responseType: 'blob', // important
});
console.log('response', response);
const url = window.URL.createObjectURL(new Blob([response.data]));
const link = document.createElement('a');
link.href = url;
link.setAttribute('download', 'bp.pdf');
document.body.appendChild(link);
link.click();
}
export default () => <div><Button onClick={() => handleClick()}>Download file</Button></div>
If I try to open the file on the server (I am on a Mac), the file is opened correctly and I see the content. However when I download the file from the browser, it gets someway corrupted or truncated, or it is missing something, because I can not open it, and I am getting the message that it is not a valid file, although I can see that the size of both files in the file system is the same, but if I inspect the binaries with an utility, I can see both files are different..
Can someone tell me what I am missing or provide an small working example?
Thank you
Upvotes: 1
Views: 5001
Reputation: 1
Solution is much easier then we thought thanks for Edo_M
The key is res => res.blob() this will make the job for you.
My backend representation (Nodejs + express):
...
module.exports=function(app){
// GET download specified pdf file
app.get('/getpdf/:uuid', middlewarefunc.authenticateToken, (req, res) => {
if(!req.params.uuid) return res.status(400).json({error:"Missing UUID param!"});
res.setHeader('Content-Type', 'application/pdf');
res.setHeader("Content-Disposition", "attachment");
res.download(`./${req.params.uuid}`, (err)=>{
console.log("Error: ", err);
});
});
}
...
My frontend solution (tested in chrome):
...
function handleDownload(e, uuid){
e.preventDefault();
fetch(`${process.env.REACT_APP_SERVER}/getpdf/${uuid}`,
{
method: 'GET',
headers: {
'Accept': 'application/pdf',
'Authorization': 'Bearer ' + session.accessToken,
'Content-Type' : 'application/json'
}
})
.then(res=>res.blob())
.then(response => {
var fileURL = URL.createObjectURL(response);
window.open(fileURL);
})
.catch(err => {
console.error(err);
alert(err.error);
});
...
// place a button to anywhere with onClick:
<button onClick={(e) => handleDownload(e, pdf_uuid)}>Download PDF</button>
...
You will get a new tab/window in the browser with the requested PDF content.
Upvotes: 0
Reputation: 7496
You can try an alternative to using a Blob.
Set the data type in the href of your link:
link.setAttribute('href', 'data:application/pdf;base64,' + text);
or
link.setAttribute('href', 'data:application/octet-stream;base64,' + text);
or if you are still getting a corrupted file, encode your content:
link.setAttribute('href', 'data:application/pdf;charset=utf-8,' + encodeURIComponent(text));
If it's text I always use:
link.setAttribute('href', 'data:text/plain;charset=utf-8,' + encodeURIComponent(text));
And don't forget to remove the dom object after downloading the file:
document.body.removeChild(link);
This is the complete code:
let link= document.createElement('a');
link.setAttribute('href', ''data:application/pdf;base64,' + text);
link.setAttribute('download', 'bp.pdf');
document.body.appendChild(link);
link.click();
document.body.removeChild(link); // Remember to remove the dom object after downloading the file
This is a fiddle showing this functionality with a base64 encoded pdf:
Upvotes: 5
Reputation: 1
I think you should change the server implementation and do something like below:
var express = require('express'); var app = express();
app.use(express.static('public')); app.use(express.static('images'));
app.listen(3000);
And then request host:3000/bp.pdf ,the file should be in the public,images folder on the root of your node application.
Upvotes: 0