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
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
Share Improve this question asked Oct 27, 2018 at 19:52 fgonzalezfgonzalez 3,8877 gold badges56 silver badges84 bronze badges 5- How big is the file you want to download? – c-chavez Commented Oct 27, 2018 at 20:36
- 178Kb, not a big one. For bigger ones I tried creating an stream and piping the stream into the response. Same problem. – fgonzalez Commented Oct 27, 2018 at 20:40
- I added an answer with an alternative, have a look and let me know if it works – c-chavez Commented Oct 28, 2018 at 14:59
- Still facing same issue. Do you have a working example with a small pdf file? Are you able to fetch it from the server, send the file to the browser, download it and open it normally? For me only works when I put the file in the public folder and reference it directly. but this should not be the solution in my opinion – fgonzalez Commented Oct 31, 2018 at 12:01
-
@fgonzales yes, I added a fiddle showing the basic download of the file. For your case of getting the file from the server, just encode it in base64, return that value (the plete string), and replace the variable
text
in my answer with that value. – c-chavez Commented Oct 31, 2018 at 12:26
3 Answers
Reset to default 5You 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 plete 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:
Fiddle
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.
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.
发布者:admin,转转请注明出处:http://www.yc00.com/questions/1745502727a4630489.html
评论列表(0条)