send file from node to client for download - javascript

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.

Related

Node js serve file body from server and download in browser

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.

I am trying to create a Download Button but file is not downloading?

I am creating download button having click listener which request server to download file
code click listener:
downloadFileClick(event){
$.ajax('/download', {data:{}}).done(function(data){
}.bind(this));
}
at server side following code is running
app.get('/download', function(req, res){
var file = __dirname + '/write/imageout.png';
res.download(file);
});
file is not downloading in browser. I checked response send from server to client it sending file content but it not downloading from browser.
You can not download a file by making an ajax request to that file. The Browser will ignore this. You have to open the file via <a href="/download" download> or you can trigger that from jQuery:
var a = $("<a>");
a.attr("href", "/download");
a.attr("download", "img.png"); // this is important
a.appendTo("body");
a[0].click();
a.remove();
This should download the browser image correctly.

NodeJS not trigger save file dialog in browser / EmberJS not receive file sent from server

My scenario:
I have an app written using MEEN stack (MySQL, ExpressJS, EmberJS, NodeJS). In a page, I have a form input. I am supposed to get the input data, send it to server, generate a PDF and display in EmberJS. The server is in NodeJS with ExpressJS, and the generated file is written to disk before getting sent to front-end.
My problem:
I cannot display the PDF file in EmberJS. Or rather, nothing is displayed. In my back-end with NodeJS and ExpressJS, I send a filestream of the PDF file back to EmberJS. Using a REST Client like Postman extension in Chrome, the dialog is called, and I can save the file. However, in EmberJS, no dialog appears, but I can see the content of the filestream using console.log in Chrome Dev Tools.
Why is it like this?
Below is my code for sending the file in NodeJS with ExpressJS.
generatePDF: function(req, res){
var details = req.body;
// #param details
// #return relative path to the file
inventoryController.generatePDF(details, function(relPath){
var filePath = path.resolve(relPath);
// This is the first method
// I explicitly specify the header for the Response Object
// and pipe the ReadableStream to the Response Object
// var name = path.basename(filePath);
// var mimeType = mime.lookup(filePath);
// res.setHeader('Content-disposition', 'attachment; filename=' + name);
// res.setHeader('Content-type', mimeType);
// var fileStream = fs.createReadStream(filePath);
// fileStream.pipe(res);
// This is the second method (currently being used)
// using sendfile() of ExpressJS, the header is automatically set
res.sendfile(filePath);
});
},
The code in Ember.js for sending details to server and getting data back.
var doc = {
// some attributes inside here
};
var url='/pdf';
var request = Ember.$.post(url, doc);
request.then(function(data){
if(data.status === 'ERR'){
// handling error
} else {
console.log('Successfully generated PDF.');
console.log(data); // I can see the filestream here
}
});
I think the problem lies that this isn't an Ember.js issue but a server issue, and how it's handled.
jQuery cannot save the file to disk, as it's a security risk. While extensions can override various security limitations, In Ember, or any other JavaScript framework (which uses jQuery) you cannot force a save as dialog as this is enforced by security. JavaScript cannot write to your local file format, (aside from html 5 local storage which is similar in many ways to cookies).
As such you cannot have a save as PDF. The only way to perhaps get that to work is allow the browser itself to capture the stream back and handle it:
You could try this plugin, but I'm not sure it works, and it's not recommended at all.
I'd recommend you just use a pure link from your browser and have the server send the file back in proper way, rather than an ajax call. You can either have a form submit it or a pure link with query string params.
Client Side:
<a href="/server/getFile?{"contentID"="123", "user" = "test#me"}>Get File</a>
or
<form action="/getFile" method="POST">
<input type="hidden" id="user" name="user" value="test#me" />
<input type="hidden" id="contentID" name="contentID" value="123" />
<input type="submit" value="Get File />
</form>
Server Side:
Add in the server the following headers:
res.setHeader('Content-disposition', 'attachment; filename=<file name.ext>');
It might be a wise idea to also add a mime-type:
res.setHeader('Content-type', '<type>/<subtype>');
full code:
var filename = path.basename(filePath);
res.setHeader('Content-disposition', 'attachment; filename='+ filename);
res.setHeader('Content-type', 'application/pdf');
// it's better to use a stream than read all the file into memory.
var filestream = fs.createReadStream(filePath);
filestream.pipe(res);
Or if you're using express you could use this helper
res.download(filePath)

Use "localhost" instead of "app://" to display files in TideSDK

Is there any way to load/display files by using 'localhost' address instead of 'app://'?
I mean something like:
http.://localhost/com.app/file.swf
I've tried using HTTPServer & FileStream listed on TideSDK documentation, but every time I try to load a file, the entire app gets blocked and stops responding.
server = Ti.Network.createHTTPServer();
//Specify port number and callback function
//This example can be tested by pointing your
//browser to http://localhost:8082/
server.bind(8082,'localhost',function(request,response) {
//Serve desired file
var contents,
contentType,
readFi = Ti.Filesystem.getFile(Ti.App.getHome()+'/flash',request.getURI());
if (readFi.exists())
{
var Stream = Ti.Filesystem.getFileStream(readFi);
Stream.open(Ti.Filesystem.MODE_READ);
contents =Stream.read();
Stream.close();
}
response.setContentType("application/x-shockwave-flash");
//Setting content length of the response
response.setContentLength(readFi.size());
//Setting status and reason
response.setStatusAndReason('200','OK');
//Finally writing the response back
response.write(contents);
});

How to set the name of a file in jquery

(This title may not be clear but whatever you read here is a refinement trying to get past the "quality standards" script, which seem to be a lot stricter based on the tags chosen)
On the client side is there any way in jquery to set the name of the file downloaded?
lets say on my server the file is stored as QXYZO123 , but the file is really information.xls , a spreadsheet. Even the hyperlink says information.xls as I have information linking the random file name to the original file name.
When the user clicks on the link, by default it will try to download the file name as stored on the server, QXYZO123, but I want it instead to say information.xls , how can I set this to suggest the file name to save as?
I call it a suggestion because based on the user's browser settings, it will either auto download with my filename suggestion or ask the user where to download and save it, with the filename suggestion
There is no setting file properties from JQuery directly. JQuery means some Javascript codes and Javascript is a client side script language. This means you can do something, only on client side, not on server side.
But there is some indirect methods to do this. First of all, only way to do this is setting the file name on server side. It depends on what language you are using on server side. Depens on server side language, You can write your own download web api. Pass the file name as a request parameter to your api and let it give you the file with your customized file name. I don't know what language you are using on server side but I prepared a serverside code with node.js that accepts customized file name in 'GET' request as parameter.
var sys = require ('sys'),
url = require('url'),
http = require('http'),
qs = require('querystring');
var path = require('path');
var mime = require('mime');
var fs = require('fs');
var server=http.createServer(
function (request, response) {
if(request.method=='GET') {
var filePath='path_to_your_file_in_your_server_file_system';
var filestream = fs.createReadStream(filePath);
var url_parts = url.parse(request.url,true);
console.log(url_parts);
var fileName= url_parts.query.fileName; //Taking your customized file name from GET request parameters.
if(!fileName)
{
fileName=path.basename(filePath);
}
var mimetype = mime.lookup(filePath);
response.setHeader('Content-disposition', 'attachment; filename=' + fileName);
response.setHeader('Content-type', mimetype);
filestream.pipe(response);
response.writeHead( 200 );
response.end();
}
}
);
server.listen( 9080 );
When you run this server code with node.js you can get file with your customized file name from the url which localhost:9080?fileName=yourCustomizedFileName. As you see we are giving the fileName 'GET' request parameter in url. You can use javascript windows.location or something else to get the file with your customized file name on client side Javascript code.
Don't let the node.js code make you confused. The point of the solution is writing a downloading api which takes fileName parameter from 'GET' request, to send the file with this name to clients.
You can apply this node.js code for your server side language or research how to apply it. Probably, It won't be hard to find and apply it.

Categories

Resources