res.download() download window not showing up - javascript

I created a download button that downloads the file on click. The problem is when I click the download button, I'm able to see the content that I want to download by using Chrome inspect -> Network -> Response but it is not opening a window to save the file to my PC.
For example, I'm trying to download text.txt which contains multiple lines of MY FILE string. I'm able to see it on Response tab but how can I download the .txt file.
Relevant React Code:
<button onClick={(e) => downloadHandler(e)}>Download</button>
let downloadHandler = (e) =>{
const fileName = e.target.parentElement.id;
fetch('http://localhost:3001/download',{
method: 'post',
headers: {'Content-Type': 'application/json'},
body: JSON.stringify({id: fileName})
})
}
Relevant Backend Code:
const uploadFolder = `${__dirname}` + `\\uploads\\`;
app.post('/download', function(req, res){
let fileName = req.body.id; // example output: 'dog.jpg'
res.download(uploadFolder+fileName, fileName); // Set disposition and send it.
});
The idea is that I will feed fileName to backend and then download it with res.download(uploadFolder+fileName, fileName); line. I think im suppose to use window.open('/download') but that just opens the homepage on a new tab or maybe I am just placing it wrong.

Okay, I have managed to solve my issue. three main modifications were made to make this code and idea work.
Changing the request from POST to GET. Another
StackOverflow thread also mentions this.
Using axios() instead of fetch().
Creating Blob object from the res.download(filePath, fileName) response value.
Anyone else having this problem with the React Code part should check this Github link.
Final State of the React function posted in the question
let downloadHandler = (e) =>{
const fileName = e.target.parentElement.id;
axios({
method: 'get',
url: 'http://localhost:3001/download/'+fileName,
responseType: 'blob',
headers: {},
})
.then((res) => {
const url = window.URL.createObjectURL(new Blob([res.data]));
const link = document.createElement('a');
link.href = url;
link.setAttribute('download', fileName);
document.body.appendChild(link);
link.click();
})
.catch((error) => {
alert(error);
})
}
Final State of the backend code posted in the question
const uploadFolder = `${__dirname}` + `\\uploads\\`;
app.get('/download/:filename', function(req, res){
let fileName = req.params.filename
const filePath = uploadFolder+fileName;
res.download(filePath, fileName);
});

Related

How can I add additional data in FormData when uploading multiple files/folder?

I am trying to upload multiple files/folder from front-end and for some reason In my back-end I want information like - File Name, File Extension, Location of File in the Uploaded Folder and so on..
Now I am able to upload multiple files/folder but my problem comes when I am looping all the selected files to append in FormData(), I also want to append information like - File Name, File Extension, Location of File in the Uploaded Folder, for individual file so that I can identify in my back-end.
this is what I am doing----:
const uploadFolder = document.querySelector('#upload-folder');
uploadFolder.addEventListener('change', async ()=>{
const url = "/home/photos/my-photos/";
let files = uploadFolder.files;
let header = {'Accept': 'application/json', 'X-Requested-With': 'XMLHttpRequest', 'X-CSRFToken': window.CSRF_TOKEN}
let formData = new FormData()
for (const key in files) {
const file = files[key];
if (file.name && file.webkitRelativePath){
const fileExtension = file.name.split(".")[(file.name.split(".").length)-1]
const filePath = file.webkitRelativePath.replace(file.name, "")
formData.append(`file-${key}`, file);
// Here I also want to append fileExtension, filePath, and also name of the file.
// I tried by giving formData.append(`file-${key}`, file, fileExtension, filePath, file.name);
// but unfortunatly it didn't work
}
}
await fetch("/home/photos/my-photos/", {method: "POST", mode: 'same-origin',
headers: header,
body: formData
})
})
You need to call formData.append() for each key you want to add.
For example:
formData.append(`file-${key}-path`, filePath)

When I open a Salesforce Attachment it is downloaded but the pdf is empty

I am getting the attachment body using the Rest API.
var config = {
method: 'get',
url: '<Domanin>/services/data/v48.0/sobjects/Attachment/00PD000000HQD68MAH/Body',
headers: {
'Authorization': `Bearer ${
accessToken
}`,
'content-type':'application/pdf'
},
};
let rawData = await axios(config);
rawData = rawData.data
I am getting the PDF data in this format
%PDF-1.5
%ÓôÌá
1 0 obj
<<
In the client side I am trying to make this as a downloadable file but I am getting blank pdf. The actual pdf contains 2 pages the downloaded pdf contains two pages as well but they are blank.
Client Side Code:
var downloadLink = document.createElement('a');
downloadLink.target = '_blank';
downloadLink.download = 'test.pdf';
// convert downloaded data to a Blob
var blob = new Blob(([rawData]), {type: 'application/pdf'});
// create an object URL from the Blob
var downloadUrl = URL.createObjectURL(blob);
// set object URL as the anchor's href
downloadLink.href = downloadUrl;
// append the anchor to document body
document.body.append(downloadLink);
// fire a click event on the anchor
downloadLink.click();
Please let me know what is wrong with the above logic
Please specify responseType: 'arraybuffer' in request config. Modify your config object to
{
method: 'get',
url: '<Domanin>/services/data/v48.0/sobjects/Attachment/00PD000000HQD68MAH/Body',
headers: {
'Authorization': `Bearer ${
accessToken
}`
},
'responseType': 'arraybuffer'
};

Multipart form Response from NodeJS Server- issue extracting some fields

I have a ReactJS Application that sends an Axios POST request to a NodeJS express server and expects a response with several fields. Specifically, I am using "form-data" in the backend to handle the data streaming.
Here is my backend response.
var FormData = require('form-data');
app.get('/test', (req, res) => {
// create a new form to send all data back to client
var form = new FormData();
form.append('results_log', 'this is text', { contentType: 'text/plain'});
form.append('results_images', fs.createReadStream('./test_results/result.zip'), { contentType: 'application/zip' });
console.log(form);
form.pipe(res);
});
In the frontend, I can download the "results_images" ZIP file from the formdata server response without any issues, but I cannot get the "results_log" field, which is just a simple string. Every attempt has resulted in a "null".
Below is the frontend code.
axios({
url: 'http://localhost:5000/test',
method: 'GET'
})
.then((response) => {
var info = response;
// this alerts NULL
alert(info.data["results_log"]);
const url = window.URL
.createObjectURL(new Blob([info.data["results_images"]]));
const link = document.createElement('a');
link.href = url;
link.setAttribute('download', 'results.zip');
document.body.appendChild(link);
link.click();
})
.catch((error) => console.log(error));
Here is part of the alert of the whole response.data field. As you can see, both fields are present in the response.
Am I doing something wrong when extracting the string field? Any help is appreciated!

Push File Download on Ajax POST Nodejs Express

On Node Server i have this code . Its basically sending the browser POST data to api server and recieves a file as chunk data and the same data is send back to browser via pipe response . But the issue is the api reponse is correct and i can write the file using nodejs locally but it doesnt push download file in browser
router.post('/MyURLOnNODE', function (req, res) {
var MyJsonData = { some Data };
res.writeHead(200, {'Content-disposition': 'attachment; filename=fileArchive.tgz','Content-Type': 'application/force-download'});
try {
request({
url: 'SomeAPI Url', //URL to hit
method: 'POST',
json: MyJsonData
}).pipe(res);
} catch(e) {
console.log("Pipe error",e);
}
console.log("File Streaming Called ",MyJsonData)
}
);
Client Side Code ...This was an attempt to create a blob and use it on urlObject. but the downloaded file is corrupted when i checked in hex.
$http({
method: 'POST',
url: 'MyURLOnNODE',
data: PostData, //forms user object
headers: {
'Content-Type': 'application/json'
}
})
.then(function (data) {
var response=data.data;
var id = Flash.create('success', "Folder Archieved", 5000);
var a = document.getElementById('arch');
a.href = URL.createObjectURL(new Blob([response]));
a.download = "FolderMe.tgz";
a.type='application/octet-stream '
a.click();
}
So is there any solution to this ? either on NodeJs Side or On browser
Update : https://stackoverflow.com/a/7969061/7078299
This thread says its hard to convert an ajax request to download file. So i need to work on client on using urlobject. But blob isnt working with stream data. How to solve it
You can use a node module called file-saver and use saveAs method provided by it and download the file on the client side.
First npm install file-saver;
You can use it as
import {saveAs} from 'file-saver';
and inside your then block you need to add this line
saveAs(new Blob([response]), <your file name>)
It will auto-download your file.
i fixed the issue by adding a reponseType on Client Side Code. Now the blob and ObjectUrl works correctly
$http({
method: 'POST',
url: 'MyUrl',
data: PostData, //forms user object
headers: {
'Content-Type': 'application/json'
},
responseType: 'arraybuffer'
})
.then(function (response) {
console.log(response);
var headers = response.headers();
var blob = new Blob([response.data],{type:headers['content-type']});
var link = document.createElement('a');
link.href = window.URL.createObjectURL(blob);
link.download = "Archive.tgz";
link.click();
});

Axios download file by the generated filename from the backend

I am using Axios to send POST request to my backend.
The backend generate an Excel file with a name e.g. testing.xlsx.
What I am trying to do:
Doing this file using the same filename generated from the backend and I have tried Postman and everything works fine.
What I have tried:
axios.post(`${env.ENDPOINT}reports/sales/customers_statement`, {
customers_id: form_data.customers_id,
from_date: form_data.from_date,
to_date: form_data.to_date,
},{
responseType: 'blob'
}).then((res) => {
const url = window.URL.createObjectURL(new Blob([res.data]));
const link = document.createElement('a');
const file_name = `${new Date().toISOString().slice(0,10)}.xlsx`; // RENAME HERE
link.href = url;
link.setAttribute('download', file_name);
document.body.appendChild(link);
link.click();
resolve(res.data);
}).catch((e) => {
reject(e);
});
This works fine but it doesn't download the file by the filename generated from the server.
In other words I want to send request to my backend to download the file by the file name already generated from my backend like when I send request using Postman.
It is because you are setting the download attribute to file_name value which is different from the filename server returned
const file_name = `${new Date().toISOString().slice(0,10)}.xlsx`;
Try changing the above to this
const contentDisposition = data.headers['content-disposition'];
const filename = contentDisposition.match(/filename=(?<filename>[^,;]+);/)[0];
link.setAttribute('download', file_name);
In the backend
response.setHeader("Content-disposition", "attachment; filename="+ yourfilenamehere);

Categories

Resources