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.
Related
I am trying to download an image from Amazon s3 using the #aws-sdk/client-s3 package. The image will download but I can't open it. I get an error and says it is an unrecognizable format.
React Component Download Function
const downloadImg = (e) => {
const href = e.target.getAttribute('img-data');
var img = href.split('/').pop();
const options = {
method: 'GET',
headers: { "Authorization" : `Bearer ${token}` },
};
fetch(`/download-img/${img}`, options)
.then(response => response.blob())
.then(blob => {
const url = window.URL.createObjectURL(blob);
const a = document.createElement('a');
a.href = url;
a.download = img;
document.body.appendChild(a);
a.click();
a.remove();
});
}
Node/Express Route
// #desc Download Screenshot
// #route get /download-img
// #access Private
app.get('/download-img/:id', authenticateToken, async(req, res) => {
const imgUrl = req.params.id;
try {
const getObjectParams = {
Bucket: awsBucketName,
Key: imgUrl,
}
const command = new GetObjectCommand(getObjectParams);
const file = await getSignedUrl(s3, command, {expiresIn: 60});
const img = axios.get(file)
.then(function (response) {
res.send(response.data)
})
.catch(function (error) {
// handle error
console.log(error);
})
} catch (err) {
console.log(err)
}
});
Response.data Output
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) {
const path = "/home/gonsa02/Disk/Projects/";
const dirname = "uploads/trainings/";
res.download(`${path}${dirname}${training.file_id}`);
}
});
And here is the React frontend code:
const downloadTraining = async (id) => {
const fileReader = new FileReader();
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((res) => {
console.log(res);
fileReader.readAsDataURL(new Blob([res.data]));
})
.catch((err) => console.log(err));
fileReader.addEventListener("loadend", () => {
const blobString = fileReader.result;
const link = document.createElement("a");
link.href = blobString;
link.setAttribute("download", "file.pdf");
document.body.appendChild(link);
link.click();
});
};
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.
maybe you can try this
fetch("filepath", {
headers: headers
})
.then(res => res.blob())
.then(blob => {
const link = document.createElement("a");
link.href = URL.createObjectURL(blob);
link.setAttribute("download", "file.pdf");
document.body.appendChild(link);
link.click();
})
I don't test it.
first of all you get file with id so the name of the file missing extension .pdf you can try this code first and setting custom name
res.download(`${path}${dirname}${training.file_id}` , "test.pdf);
if this is not working try to send file not download
var data =fs.readFileSync(`${path}${dirname}${training.file_id}`);
res.contentType("application/pdf");
res.send(data);
I think you need to change the response type to 'arraybuffer', responseType: 'arraybuffer' at least that work for me in a similar situation.
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...
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'
})
}
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