React+Node Express, downloaded docx file is corrupted - node.js

I've read through alot of similiar questions, tried alot of suggested solutions, and none worked for me. So, i send the file from the backend using "res.download('directory/' + filename)", and judging from the response headers, i do get the correct file. There are no other files in the folder i'm sending from, and the original file is 14KB. However the 'data' part of the response is around 21KB. This is what i do with the response on the web app to get the file:
await axios.get(`api` + file.id,
{headers: {'x-access-token': token}}, { responseType: 'arraybuffer' }
).then((response) => {
const url = window.URL.createObjectURL(new Blob([response.data])); //specifying the type here doesn't help
const link = document.createElement('a');
link.href = url;
link.setAttribute('download', `${filename}`); //filename = the name of the file i'm trying to download
document.body.appendChild(link);
link.click();
link.parentNode.removeChild(link);
})
And the file i get in result is also around 21KB, and does not open in word due to it being corrupt.

Fiddled a bit with the axios.get syntax, put the "responseType" togather with the config which has headers. And now the file i get is not corrupted o_o
axios.get(`api/` + file.id,
{
headers:
{
'x-access-token': token
},
responseType: 'arraybuffer'
}
)
At first i thought that the file size was different, but it's not. So that definately fixed it lol. That's what i get from being a noob in js.

You may need to add the file extension at the end of the filename like this:
link.setAttribute('download', `${filename}.docx`);

Related

Axios Excel file download using POST has missing rows

I'm trying to download an Excel file using an axios POST request. The backend seems to be working fine as I can download the Excel file using Swagger UI and Postman. The problem happens when I try to download using axios and I only get an Excel file with headers but missing all the rows of data. Here is my axios request:
await axios.post(API.viewReport.reportsNotLoginExcel, { data: data },
{
responseType: 'arraybuffer', // Important
}
).then(async (response) => {
let blob = new Blob([response.data], {type:'application/vnd.ms-excel'});
const url = URL.createObjectURL(blob);
const link = document.createElement("a");
link.href = url;
link.setAttribute("download", "file.xlsx");
document.body.appendChild(link);
link.click();
link.remove();
});
I have tried both responseType: 'arraybuffer' and responseType: 'blob'
And here is my Spring controller:
#PostMapping(path = "/reports/not-login/excel", produces = "application/vnd.ms-excel")
public ResponseEntity<Resource> doDownloadNotYetLogin(#RequestHeader(value = "iv-user") String ivUser,
#Valid #RequestBody DownloadRequest downloadRequest) {
InputStreamResource file = new InputStreamResource(viewReportService.doDownloadNotYetLogin(downloadRequest));
String filename = "NotYetLoginReport.xlsx";
return ResponseEntity.ok().header(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename=" + filename)
.contentType(MediaType.parseMediaType("application/vnd.ms-excel")).body(file);
}
In both Swagger UI and Postman, I am able to download the file with the correct data, so I assume there is nothing wrong with my backend.
Excel file with correct data
But downloading the file using axios gives me a file with only the headers and no rows of data.
Excel file with missing rows of data
There are no error messages or warnings from either frontend or backend.
I've tried external libraries like js-file-download and solutions from other posts but so far with no luck. I'm confused because I am able to get the file but somehow part of it is missing, and I haven't found any post facing this problem either.
Do let me know if any other information would be useful to show.

Getting a bad request 400 when trying to upload zipped wkt file to here-maps rest api

We have a problem with the fleet.ls.hereapi.com when uploading a new layer for geofencing.
const myId = 'MYLAYER'; // just a id to check
zip.file('data.wkt', `NAME\tWKT\n${myId}\t${wkt}`);
const content = await zip.generateAsync({ type: 'nodebuffer' });
const formData = new FormData();
formData.append('zipfile', content);
await axios.post(config.HERE_MAPS_UPLOAD_ENDPOINT, formData, {
headers: {
'content-type': 'multipart/form-data',
},
params: {
apiKey: config.HERE_MAPS_REST_API_KEY,
layer_id: myId,
},
});
We get a bad request without a message and do not know what the problem is. The same implementation works in the Frontend (with 'blob' as zip type). Is there a parameter to get a better error message from the api?
We got the instructions how to implement it from this tutorial: https://www.youtube.com/watch?v=Ayw9GcS1V-8 and as I mentioned it works fine in the frontend. Also it works if I write a file in node and upload it via curl. Thank you for any help in advance!
Edit: I'm getting the following issue from the API: 'Multipart should contain exactly one part but contains 0'
I fixed it!
The problem was that the api needed a filename for the form data. This filename can be provided as third parameter as described here.
So I basically changed formData.append('zipfile', content); to formData.append('zipfile', content, zipfile.zip); and it worked.
Hope this will help somebody in the future!

Option to user to download excel file in Angular

How to download a excel file from server on button click in Angular 8. I am new to Angular and I read through different posts which said to file-saver library. Do we need to install a library to work out download option or not. Can anyone please share the code and insights.
You can use this for example:
const resp = await this.httpClient.get(`{yourendpoint}`, { responseType: 'blob' }).toPromise();
const url = window.URL.createObjectURL(resp);
window.open(url);
If your getting blob from you backend then you can do something like this:
let a = document.createElement('a');
a.href = URL.createObjectURL(data);
a.download = 'FILE_NAME';
document.body.appendChild(a);
a.click();
document.body.removeChild(a);
Where 'data' is response from your api.
PS: Don't forget to add header responseType: 'blob'

How to download mp3 file from a url that redirects? (In Node.js)

I retrieve this URL from using some previous logic - https://bots.rocket.chat/file-upload/ZSzGtWdXyP8DZwrQ9/Audio%20record.mp3
Now I need to download it for further processing, but I tried using the download, axios.request, and other packages available. My best guess for them failing is that the actual URL of the audio is different then what I retrieved.
Something like (It changes after a while) -https://s3.amazonaws.com/uploads.use1.cloud.rocket.chat/KqCQiHfeFaKdSEGvy/uploads/GENERAL/XmYemgXfudSzBQstR/ZSzGtWdXyP8DZwrQ9?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Credential=AKIAILPK6SHTK5RJZLHQ%2F20190518%2Fus-east-1%2Fs3%2Faws4_request&X-Amz-Date=20190518T115900Z&X-Amz-Expires=120&X-Amz-Signature=8d793d14fbb33d78b084a5ed153106ba19440feb7bf05525aeed530b5a0907f9&X-Amz-SignedHeaders=host
Also, I'm able to download the file using the same code when I provide it with the end URL (the longer one).
So need to figure out how to reach that URL in node.
Also to access the first URL you need to make an account on https://bots.rocket.chat
This is the code I have currently. The url passed to getFile function is the is a relative path which I append to the prefix url to form the above mentioned shorter URL, and call axios and this doesn't work.
But when I replace the url with a long url which is similar to the longer one posted above the code works just fine.
async function getFile(url) {
var fs = require('fs');
return await axios.request({
responseType: 'arraybuffer',
followAllRedirects: true,
url: `https://bots.rocket.chat${url}`,
method: 'get',
headers: {
'Content-Type': 'audio/mpeg',
},
}).then((result) => {
const outputFilename = 'file2.mp3';
fs.writeFileSync(outputFilename, result.data);
return outputFilename;
})
.catch(err => console.log(err));
;
}

Downloading files from expressJS (sendFile) server to VueJS, is returning corrupted files?

I have an API written in expressjs, that sends a file when provided with a fileID.
The backend is working fine, as it sends the correct file (uncorrupted) when the route url is typed directly int the browser.
ex. http://localhost:8080/download?id=1234 (downloads all files just fine ie.txt, xlsx, jpg, zip)
My express route actually uses res.download, which is really jsut a wrapper for sendFile.
When I try calling these route urls from a Vue http get request, it only returns txt files uncorrupted. All other files download, but they can be opened, due to corruption.
Can anyone please point me in the right direction as to why its not working in Vue?
For clarity, "item" is passed as an argument to this function.
this.$http.get("http://localhost:8000/files/download", {params:{id:item._id}}, {responseType: 'arraybuffer'})
.then(response => {
var blob = new Blob([response.data], {type:response.headers.get('content-type')});
var link = document.createElement('a');
link.href = window.URL.createObjectURL(blob);
link.download = item.filename;
link.click();
})
For reference, this is my express route
Shout out to #Helpinghand for helping me troubleshoot this.
"I found the solution within the link you posted. The problem is that i was explicitly sending params in its own object before assigning "content-type". The example you posted concatenates the query params to the url. After making this switch, its working perfectly".
this.$http.get(`http://localhost:8000/files/download?id=${item._id}`, {responseType: 'arraybuffer'})
.then(response => {
console.log(response.headers.get('content-type'));
console.log(response);
var blob = new Blob([response.body], {type:response.headers.get('content-type')});
var link = document.createElement('a');
link.href = window.URL.createObjectURL(blob);
link.download = item.filename_version;
link.click();
})

Resources