React.js download pdf file from node backend - node.js

I have code that just downloads a file that exists in my backend. I can see the pdf on the backend is created properly and in the right place, but when I send and download the file to the frontend and open it I get the error "Failed to load pdf document" no matter which browser I use. I think this must mean there is something wrong with my blob downloading code since I can open and see the file on the backend, but I can't figure it out. I have tried following many examples online and I get the same issue regardless of what I have tried.
server.js (node backend file)
app.get('/api/v1/getPdf', function(req, res) {
let resolve = require('path').resolve
res.sendFile(resolve('./tickets/tickets.pdf'));
});
PrintDetails.js (React js code for downloading pdf) - Note: I only included the relevant parts
class PrintDetails extends React.Component {
async printTickets() {
let file = await getTicketsPdf();
console.log(file);
const blob = new Blob([file], {type: 'application/pdf'});
const link = document.createElement('a');
link.href = window.URL.createObjectURL(blob);
link.download = 'tickets.pdf';
document.body.appendChild(link);
link.click();
setTimeout(function() {
document.body.removeChild(link);
}, 100);
}
render() {
return (
<div>
<button className="download-button-icon" onClick={this.printTickets}>Download</button>
</div>
)
}
async function getTicketsPdf() {
let data = {};
await (async () => {
const rawResponse = await fetch('/api/v1/getPdf', {
method: 'get',
headers: {
'responseType': 'blob',
'Content-Type': 'application/json'
},
});
data = await rawResponse;
})();
return data;
}

Here's my implementation using axios and file-saver.
Node.js backend
app.get('/api/v1/getPdf', function(req, res) {
res.download('./tickets/tickets.pdf');
});
React frontend
import { saveAs } from 'file-saver'
.
.
.
async function printTickets() {
const { data } = await getTicketsPdf()
const blob = new Blob([data], { type: 'application/pdf' })
saveAs(blob, "tickets.pdf")
}
async function getTicketsPdf() {
return axios.get('/api/v1/getPdf', {
headers: {
'Content-Type': 'multipart/form-data'
},
responseType: 'arraybuffer'
})
}

Related

how to download an excel file in react from NodeJS

I have a nodeJs server and react app. and in my NodeJs I am returning an excel file and I was able to download it in postman when clicking send and download. But in react the file is download but give error when openning that it is corrupt
Here is my implementation in ReactJS (Thats making the issue)
export const exportUsersToExcel = async (token) => {
try {
axios
.get(
`${process.env.REACT_APP_SERVER}/api/dashboard/users/excel`,
{
headers: { "auth-token": token },
},
{ responseType: "blob" }
)
.then((response) => {
const url = window.URL.createObjectURL(new Blob([response.data]));
const link = document.createElement("a");
link.href = url;
link.setAttribute("download", "Users.xlsx");
document.body.appendChild(link);
link.click();
});
} catch (error) {
console.log("Error Exporting Users");
return error;
}
};
and I am sending the file in NodeJS like this
res.set({
"Content-disposition": `attachment; filename=Users.xlsx`,
"Content-Type":
"application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
});
return workbook.xlsx.write(res).then(() => {
res.status(200).end();
});
I had a similar problem, and I solved it with the following (React) code:
Axios
export const getFile = async () => {
return await api.get<any>(`${PATH_API}`, {
responseType: 'arraybuffer',
headers: {'Content-Type': 'blob'},
});
};
Function in .tsx file
const downloadFile = async () => {
const resp = await getFile();
const link = document.createElement('a');
const fileName = 'file.extension';
link.setAttribute('download', fileName);
link.href = URL.createObjectURL(new Blob([resp.data]));
document.body.appendChild(link);
link.click();
link.remove();
};
Render function
<a onClick={() => downloadExceptionFile()} href="#" download>
download
</a>
The ploblem with this is that URL.createObjectURL() is deprecated. I don't know how to resolve this at this point.

Why does fs.readFile return null for first fetch call?

I have a simple function to return a pdf file on my server which works as expected but not the first time the page loads. The first time I try to download the file, the server console log shows me it's there, but the React page console has null. If I click on the download link again, the file contents are returned. Can someone help me please?
React function that calls getDocByLoc (which is itself called by a button click)
async function fetchInvoice(fileLocation) {
setInvoiceStatus('loading');
setInvoice(await invoiceService.getDocByLoc({ location: fileLocation }));
setInvoiceStatus('succeeded');
downloadFile(invoice);
}
// download file
function downloadFile(invoice) {
if (invoiceStatus === 'succeeded') {
let url = window.URL.createObjectURL(invoice);
let a = document.createElement('a');
a.href = url;
a.download = 'test.pdf';
a.click();
}
}
React fetch code
function getDocByLoc(location) {
return fetchWrapper.getDocument(`/invoices/document`, location);
}
fetchWrapper code
function getDocument(url, location) {
const requestOptions = {
method: 'POST',
headers: {
Accept: 'application/json, application/x-www-form-urlencoded',
'Content-Type': 'application/json',
...authHeader(url),
},
credentials: 'include',
body: JSON.stringify(location),
};
return fetch(`${AppSettings.serverEndpoint}${url}`, requestOptions).then(
handleResponseForDocuments
);
}
Node file reader code
function getDocumentByLocation(req, res, next) {
const { location } = req.body;
fs.readFile(location, (err, data) => {
if (err) res.status(500).send(err);
console.log('data: ', data);
res
.contentType('application/pdf')
.send(
`data:application/pdf;base64,${new Buffer.from(data).toString(
'base64'
)}`
);
});
}

How to download files with NodeJS backend and React frontend? (I get the files corrupted)

I would like to be able to send pdf files with nodejs to the frontend. But when I do this, I get an error and I can't open the file. This is the error (translation of error: an error occurred when loading the PDF document):
I think that all is well but still without working.
Here is the nodeJS code:
routerTrainer.get("/download-training", verifyJWT, async (req, res) => {
const { training_id } = req.headers;
let training = await Training.findOne({
where: { id: training_id },
});
if (training) {
res.download(`${path}${dirname}${training.file_id}`);
}
});
And here is the React frontend code:
const downloadTraining = async (id) => {
const JWT = new ClassJWT();
const axiosReq = axios.create();
await JWT.checkJWT();
axiosReq
.get(`${serverPath}/download-training`, {
headers: {
training_id: id,
token: JWT.getToken(),
responseType: "blob"
},
})
.then((response) => {
const url = window.URL.createObjectURL(new Blob([response.data]));
const link = document.createElement("a");
link.href = url;
link.setAttribute("download", "file.pdf");
document.body.appendChild(link);
link.click();
})
.catch((err) => console.log(err));
};
Don`t worry about all that have JWT like verifyJWT or ClassJWT, this are implementations of json web tokens and it works correctly.
If anyone know how to fix it, please let me know.
you have to convert the binary file to a blob (in this example is set the responseType of xhr as blob), then convert it to base64 encoded file, here is an example:
<html>
<body>
<h1><a>dl</a></h1>
<script>
const pdfSrc = "https://blahblah.com/e-book.pdf";
const linkTag = document.querySelector("a");
const xhr = new XMLHttpRequest();
const fileReader = new FileReader();
xhr.open("GET", pdfSrc);
xhr.responseType = "blob";
xhr.addEventListener("loadend", () => {
fileReader.readAsDataURL(xhr.response);
});
fileReader.addEventListener("loadend", (event) => {
const base64File = event.srcElement.result;
linkTag.href = base64File;
linkTag.setAttribute("download", "file.pdf");
});
xhr.send();
</script>
</body>
</html>
In my case, in back-end (ExpressJs) I have something like -
app.get('/api/v1/getPdf', function (req, res) {
let resolve = require('path').resolve;
res.download(resolve('./folder/file.pdf'));
});
and in ReactJS (without TypeScrypt), I'm using native fetch instead of axios:
const onButtonClick = async () => {
let file = null;
await (async () => {
const rawResponse = await fetch('http://<host:port>/api/v1/getPdf', {
method: 'get',
headers: {
'Content-Type': 'application/json',
},
});
file = await rawResponse.blob();
})();
const pdfWindow = window.open();
pdfWindow.location.href = window.URL.createObjectURL(file);
};
where in component
return (
<>
<center>
<h1>Welcome</h1>
<h3>Click on below button to download PDF file</h3>
<button onClick={onButtonClick}>Download PDF</button>
</center>
</>
);
and it opens in the new window pdf file like (see link)
enter image description here
if you want to download file, you must implemente onButtonClick a little bit different
const onButtonClick = async () => {
let file = null;
await (async () => {
const rawResponse = await fetch('http://<host:port>/api/v1/getPdf', {
method: 'get',
headers: {
'Content-Type': 'application/json',
},
});
file = await rawResponse.blob();
})();
// const pdfWindow = window.open();
// pdfWindow.location.href = window.URL.createObjectURL(file);
const a = document.createElement('a');
a.href = window.URL.createObjectURL(file);
a.download = 'file.pdf';
document.body.appendChild(a);
a.click();
document.body.removeChild(a);
};
On my side it works like a charm...

multer, react-native image upload not working

I am trying to upload a picture with an image picker. I made an image component and make an image-picker fill the component, but uploading the image data to the server doesn't work.
this is the code that is called by onPress attached to a button:
const handlePhoto = async () =>{
if(image!== null){
console.log(image)
const fileToUpload = image;
const data = new FormData();
data.append('name', 'Image Upload');
data.append('file', fileToUpload);
let res = await fetch(
'http://localhost:3000/user/pic_upload',
{
method: 'post',
body: data,
headers: {
'Content-Type': 'multipart/form-data; ',
},
}
);
let responseJson = await res.json();
console.log(responseJson,'result')
if (responseJson.status == 1) {
alert('Upload Successful');
}
} else {
alert('Please Select File first');
}
}
and at index file for user router:
const upload=multer({
storage:multer.diskStorage({
destination:function(req,file,callback){
callback(null,'uploads/')
},
filename:function(req,file,callback){
callback(null,new Date().valueOf()+path.extname(file.originalname))
}
}),
});
router.post('/pic_upload', upload.single('file'), controller.picUpload)
and picUpload router just has console.log
What should I fix to make it work?

How client(React) download excel file in NodeJS?

I have two separate projects. Client: React, Server: NodeJS
I create excel on the NodeJS side by submitting a form by React.
I want to download this excel from React side. However, I couldn't download it.
NodeJS code
res.setHeader('Content-Type', 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet');
res.setHeader("Content-Disposition", "attachment; filename=" + "Report.xlsx");
workbook.xlsx.write(res)
.then(function(){
res.end();
});
NodeJS return network layer
First try React.js code
startDownload(response,"resobyte.xlsx")
function startDownload(file, fileName) {
const url = window.URL.createObjectURL(new Blob([file]));
const link = document.createElement('a');
link.href = url;
link.setAttribute('download', fileName);
document.body.appendChild(link);
link.click();
link.parentNode.removeChild(link);
}
Second try React.js code
let blob = new Blob([response], {type: 'vnd.openxmlformats-officedocument.spreadsheetml.sheet;charset=utf-8'});
FileSaver.saveAs(blob, 'fileName.xlsx");
The file has been downloaded.
My React Service Call
export const createExcel = async (model) => {
let response = () => {
return new Promise(function(resolve, reject) {
fetch(API_URL + '/api/excel/create', {
method: 'POST',
responseType: 'arrayBuffer',
headers: {
'Content-Type': 'application/json',
'x-access-token' : TokenService.getToken()
},
body: JSON.stringify(model),
}).then(response => {
resolve(response);
});
});
};
let responseData = await response();
return responseData;
}
Error open excel file

Resources