Node js serve file body from server and download in browser - javascript

I have a file repository and when i call it from the browser it automatically downloads the file and this is fine.
But i want to do this request on my server, and then serve the file result to the browser. Here is the example of the get request from my server.
downloadFile(req , res , next) {
let options = {
url: 'url to my file repo',
};
request(options, function (err, resp, body) {
if (err) {
res.status(500).send("");
return
}
for (const header in resp.headers) {
if (resp.headers.hasOwnProperty(header)) {
res.setHeader(header, resp.headers[header]);
}
}
resp.pipe(res);
})
}
The request is working fine, and when i access my server from the browser it starts downloading the file. Everything seems to work fine except one thing, the file can't be opened. This file format can't be opened, says me the image player (if the file is image for example).
Where is the problem, Is it the way i serve the file from the server?
Thank you in advance. I lost a lot of time and can't find the solution.

Because what you probably want to send is the body of the request (e.g. the data of your image).
So instead of resp.pipe(res):
res.send(body)
Use the developer mode of your browser to check the network messages passing between the server and your browser.

Related

Downloading a zip file from a given path in express api + react

So I'm completely lost at this point. I have had a mixture of success and failure but I can't for the life of me get this working. So I'm building up a zip file and storing it in a folder structure that's based on uploadRequestIds and that all works fine. I'm fairly new to the node but all I want is to take the file that was built up which is completely valid and works if you open it once it's been constructed in the backend and then send that on to the client.
const prepareRequestForDownload = (dirToStoreRequestData, requestId) => {
const output = fs.createWriteStream(dirToStoreRequestData + `/Content-${requestId}.zip`);
const zip = archiver('zip', { zlib: { level: 9 } });
output.on('close', () => { console.log('archiver has been finalized.'); });
zip.on('error', (err) => { throw err; });
zip.pipe(output);
zip.directory(dirToStoreRequestData, false);
zip.finalize();
}
This is My function that builds up a zip file from all the files in a given directory and then stores it in said directory.
all I thought I would need to do is set some headers to have an attachment disposition type and create a read stream of the zip file into the res.send function and then react would be able to save the content. but that just doesn't seem to be the case. How should this be handled on both the API side from reading the zip and sending to the react side of receiving the response and the file auto-downloading/requesting a user saves the file.
This is what the temp structure looks like
There is some strategies to resolve it, all browser when you redirect to URL where extension ending with .zip, normally start downloading. What you can do is to return to your client the path for download something like that.
http://api.site.com.br/my-file.zip
and then you can use:
window.open('URL here','_blank')

send file from node to client for download

I am using an ajax call from browser
so, on button click
a function is called
for route '/file'
app.get('/filez',function(req,res){
var id = req.params.id;
console.log('id is : ',id);
var video = ytdl(url, { filter: (format) => format.container === 'mp4' })
.pipe(fs.createWriteStream('video.mp4'));
res.download('video.mp4');
now, the file is being downloaded to the server at the moment.
but what I want to do is to send the file so the client can download it from browser.
i dont want the file to be downloaded to the server.
Here's the ajax request I made from the browser using a button click.
and I want to get the file as the response which can be downloaded to the client computer.
function myAjaxCall(){
var xhr = new XMLHttpRequest();
xhr.onreadystatechange = function(){
if(xhr.readyState ===XMLHttpRequest.DONE && xhr.status ===200){
console.log('response has come',xhr.response);
return xhr.response;
}
};
xhr.open('GET','/filez',true);
xhr.send();
};
EXPLANATION : well, not really. i was thinking more along these lines - so on button click an ajax call is sent to server and it's supposed to get back a response. I want the file to be sent via this response.
so, how do I accomplish this?
pass the get request in a href tag and it will download the file to the client , you are writing the file in server side so it is being created their , you have to have the file been created on the server side and then serve the file through res.download to the client side and later delete the file from the server side to download the file in clinet side
suppose your url looks like http://getsomefile.com/xyz?newfile=video.mp4 then in your client sides a tag you can have this url as on some domain http://getsomefile.com with route xyz to serve the file
<a href="http://getsomefile.com/xyz?newfile=video.mp4" download>
where i am assuming on client side you have some route defined as
app.get('/xyz,function(req,res){
var file = req.query.newfile;
})
and then you can use fs.unlink to delete the files through a cron like or have a manual cleaner used or do something like this
app.get('/xyz', function(req, res){
var file = req.query.newfile
res.download(realFilepath, file , function(err) {
if (!err) {
fs.unlink(realFilepath);
}
});
});
realFilepath is the actual path of file kept in server , which you can gracefully delete after the file has been served.

JavaScript Prompt download in browser

Im simply trying to download a file from the server and prompt the download in the browser for the user to see.
What i have right now:
Client
export function downloadTemplateAction(questionnaire) {
return dispatch => {
dispatch(downloadTemplateRequestAction(questionnaire));
return request
.get(downloadGETUrl)
.end((err, res) => {
if (err) {
console.log("Download ERROR", err)
dispatch(downloadTemplateFailureAction(err, questionnaire));
} else {
console.log("Download Success", res.body)
dispatch(downloadTemplateSuccessAction(res.body, questionnaire));
}
});
}
}
Server:
export function downloadTemplateDocument(req, res){
res.download('template/Example.docx');
res.end();
}
Im facing two problems:
First: When trying to download the file via the function of the Client, the response body is null but success and nothing more happens.
Second: When contacting the get API via the browser localhost:3002/api/download, the download works but the received file is empty. There should be text in it.
What am i doing wrong here?
Browser can't prompt a download progress because your request is sent via XMLHttpRequest.
Physical access to the file is needed for the browser to be aware of any download.
You could use download attribute to tell browser to download linked ressource.
original answer

Download Csv file on front end after clicking on button using angularjs , nodejs ,expressjs

I want to download .csv file on frontend.
this is my code:
$http.get('/entity/consultations/_/registerationReport' )
.success(function (data) {
myWindow = window.open('../entity/consultations/_/registerationReport', '_parent');
myWindow.close();
});
and I use json2csv converter to write in csv file.
json2csv({data: report, fields: fields}, function (err, csv) {
if (err) throw err;
res.setHeader('Content-Type', 'application/csv');
res.setHeader("Content-Disposition", "attachment; filename=" + "Report.csv");
res.end(csv, 'binary');
});
but it prints data of csv file on browser instead of downloading csv file.
#Pawan, there's nothing wrong with your json2csv function. The issue is the fact that you're trying to trigger the download with an XMLHttpRequest (XHR) request using Angular's $http service. An XHR call suggests that your code will be handling the response from the server. As such the Content-Disposition headers are ignored by the browser and do not trigger a download on the browser.
From what I can tell you have several options:
If you don't have any pre-processing to do on the client, why not just use a direct link to /entity/consultations/_/registerationReport (using and <a> tag),
You may also write $window.open(...) from your Angular code (this will have the ugly side effect of a flashing popup tab or window)
There are probably a number of other solutions, but these are the only ones that immediately come to mind. The bottom line is that XHR is not the right tool for the task you're trying to accomplish.

Moving to s3 storage with node.js

I'm trying to get ready to move a node.js application I've been working on into a production environment (I'm using Heroku). Users add images to the site via url. Right now they are just saved on the server- I'd like to move the storage to s3 but am having some difficulties.
The idea is to save the image to disk first and then upload it, but I'm struggling to find a way to be notified when the file has finished writing to the disk. It seems like it doesn't use the typical node callback style.
Here is the code as it is now. I'm using the request node module which may be complicating things rather than simplifying them:
requestModule(request.payload.url).pipe(fs.createWriteStream("./public/img/submittedContent/" + name));
// what do I do here?
fs.readFile("./public/img/submittedContent/" + name, function(err, data){
if (err) { console.warn(err); }
else {
s3.putObject({
Bucket: "submitted_images",
Key: name,
Body: data
}).done(function(s3response){
console.log("success!");
reply({message:'success'});
}).fail(function(s3response){
console.log("failure");
reply({message:'failure'});
});
}
});
Any advice would be appreciated. Thanks!
Try listening for the finish event on the writable stream:
requestModule(request.payload.url).pipe(fs.createWriteStream("./public/img/submittedContent/" + name)).on('finish', function(){
// do stuff with saved file
});
Unless you're modifying the image, you shouldn't upload to Heroku - but rather directly to S3.
See Direct to S3 File Uploads in Node.js

Categories

Resources