Express js: How to download a file using POST request - javascript

When I use GET, everything works fine. However, I struggle to use POST to achieve the same effect. Here are the code I have tried:
1.
app.post("/download", function (req, res) {
res.download("./path");
});
2.
app.post("/download", function (req, res) {
res.attachment("./path");
res.send("ok");
});
3.
app.post("/download", function (req, res) {
res.sendFile("./path");
});
None of them work. What is the correct way to do this?
EDIT:
I submit a POST request through a HTML form to /download. ./path is a static file. When I use code in method 1, I can see the correct response header and response body in the developer tool. But the browser does not prompt a download.

This might not be exactly what you want, but I have been having the same trouble.
This is what I did in the end:
Client - See EDIT below for updated client code
$http.post('/download', /**your data**/ ).
success(function(data, status, headers, config) {
$window.open('/download'); //does the download
}).
error(function(data, status, headers, config) {
console.log('ERROR: could not download file');
});
Server
// Receive data from the client to write to a file
app.post("/download", function (req, res) {
// Do whatever with the data
// Write it to a file etc...
});
// Return the generated file for download
app.get("/download", function (req, res) {
// Resolve the file path etc...
res.download("./path");
});
Alternatively, have you just tried calling $window.open(/download); from the HTML? This was the main reason why my download did not start. It returned in the XHR and I could see the data, but also did not prompt a download.
*EDIT:
The client code was not accurate, after some more testing it turned out that I only needed to do the following on the client:
// NOTE: Ensure that the data to be downloaded has
// already been packaged/created and is available
$window.open('/download'); //does the download

Related

Download File using express and fetch doesn't work

I try to download a file using nodejs and Javascript.
When I call the URL in the Browser, the file gets downloaded.
When I call this Endpoint in my javascript file using fetch, the download doesn't work
NodeJS Endpoint
app.get("/download", function (req, res, next) {
res.download(
filepath
);
});
Javascript Call
const downloadFile = async (path) => {
await fetch("http://localhost:8080/download", {
method: "Get",
})
.then((response) => {
console.log(response);
})
.catch((error) => {
console.log(error);
});
};
Do you have any suggestions?
Thank you very much!
When you make a request using Ajax then the response is passed back to the JavaScript code for handling.
If you want to do something with the file the server has sent you, then you need to write JavaScript to do something with it.
Your JavaScript logs the response object then stops.
The browser will only automatically render it in the viewport / save it to downloads if you type the URL into the address bar / click a link / etc. Doing Ajax explicitly avoids that automatic handling.
So the solution here is: Don't use Ajax. Use a link, or assign a value to location, etc.

Download a file from REST API with Restangular request

I've got a simple node.js + Restify backend with standard CORS settings and this endpoint:
var file = '1,5,8,11,12,13,176,567,9483';
server.get('/download', function(req, res, next) {
res.set({"Content-Disposition": "attachment; filename='numbers.csv'"});
res.setHeader("Content-type", "text/csv");
res.send(file);
return next();
}, function(err) {
res.send(err);
});
What it's suppose to do is to is to create CSV file and return it.
It works great when I simply type in the endpoint address to web browser and hit enter. The file gets downloaded properly.
But when I try to do the same thing, but instead of using browser's address bar I use Restangular like that:
Restangular.one('download').get().then(function (res) {
console.log(res);
});
it just writes response to console, but no file is being downloaded.
Is there a way to do this using Restangular? Or maybe I need to use something else for this?
I am not sure if Restangular can do that, but I am using FileSaver script for stuff like that. Add Filesaver to your HTML head and then:
Restangular.one('download').get().then(function (res) {
var file = new Blob([res], { type: 'text/csv' });
saveAs(file, 'something.csv');
});

Testing if download is successful with supertest

I'm testing my API endpoints with supertest, and it works great, but i can't figure out how to test if a file download is successful.
In my routes file i have defined the endpoint to be:
app.get('/api/attachment/:id/file', attachment.getFile);
and the function getFile() looks something like this:
exports.getFile = function(req, res, next) {
Attachment.getById(req.params.id, function(err, att) {
[...]
if (att) {
console.log('File found!');
return res.download(att.getPath(), att.name);
}
Then, in my test file, I try the following:
describe('when trying to download file', function() {
it('should respond with "200 OK"', function(done) {
request(url)
.get('/api/attachment/' + attachment._id + '/file');
.expect(200)
.end(function(err, res) {
if (err) {
return done(err);
}
return done();
});
});
});
I know for sure that the file is found, because it logs out File found!. It also works fine if i try manually, but for some reason, mocha returns Error: expected 200 "OK", got 404 "Not Found".
I've experimented with different mime-types and supertest .set("Accept-Encoding": "*"), but nothing works.
Anyone know how to do this?
Either the problem has been fixed in the libraries, or there is a bug in some other part of your code. Your example runs fine, and gives
when trying to download file
File found!
✓ should respond with "200 OK"
When testing for a download file, it is not enough to validate the response status from the server, it will be even better if you can somehow validate the response data.
For download data, the content of the file are usually passed in the http response as text, with the file type as Content-Type, and the attachment and filename stored in Content-Disposition.
Depending on how detailed you would like to go, you can try the following:
const response = await request(url)
.get('/api/attachment/' + attachment._id + '/file');
expect(response.headers["content-type"]).toEqual("image/png");
expect(response.text).toMatchSnapshot(); // Use only if the file is deterministic.
Using jest or any other snapshot framework, you can achieve a more reliable test.
This may be coming late, but I'm dropping this here for future reference and to help others who might be facing something similar.

Download a file from Angular.js with Express.js

In my MEAN application I need to provide a link to download a file, the link must be hidden and not accessible by unauthorized users.
So I came up with this idea of keeping the files inside the server directory and let Angular.js send with ng-click="download()" an $HTTP request to express.js with the file ID to download, and (possibly) the user id/pwd.
First of all is this a safe solution?
Second, here is my code that doesn't work, there are no errors whatsoever, but I can't even get the download dialog box to open:
Client Side
$scope.download=function(){
$http({method:'GET', url:'/download/'+image[0]['_id']}).
success(function(data, status, headers, config) {
var element = angular.element('<a/>');
element.attr({
href: 'data:attachment/csv;charset=utf-8,' + encodeURI(data),
target: '_blank',
download:'test.csv'
})[0].click();
}).
error(function(data, status, headers, config) {
});
}
Server Side
app.namespace('/download/:documentID*', function() {
app.all('/', function(req, res, next){
res.download('images/download/test.tif', 'test.tif', function(err){
if (err) {
} else {
next();
}
});
});
})
Last time I checked you couldn't trigger a download via ajax. ;-)
You'll need to create a <a> with e.g. target="_blank" so it opens up in a new tab/window. Don't know about your authentication though, I wouldn't send them in cleartext. You could work around that by checking the credentials in your ajax request and then open a new tab/window so that the file can be downloaded with some kind of one-time token. You'll need some server-side changes ofc.

Getting Data from Node.js file and displaying it in HTML/JS page

I am new to Node.js and this is my first project with it.
I have made a node.js file named test.js. It has an array say a.
Now I want to make a HTML file that calls this test.js on button click event. Then get the data from that file and publish it on a table in the HTML file.
I have already written the node.js file and I can see the results on console.log(a). But I cant understand how to send this array to HTML when it will ask for it.
Meanwhile, I googled and made up some code. The request reaches the server but I always get error response from server. Why so?
Client Side -
function fetch() {
$.ajax({
type: 'POST',
url: "http://127.0.0.1:8888",
data: 'China',
datatype: 'json',
success: function (data) {
alert("hi");
var ret = jQuery.parseJSON(data);
$('#q').html(ret.msg);
},
error: function (xhr, status, error) {
alert("hii");
}
});
Server side :
http.createServer(function(request, response) {
console.log("Request received");
response.writeHeader(200, {"Content-Type": "application/json"});
request.on('data', function (chunk) {
console.log(chunk.toString('utf8'));
consol.log(result);
response.write(JSON.stringify({data : result}));
});
response.end();
}).listen(8888);
I can see China on the console.But I dont get back the result array back to the client. Here result is an array and I get its value on the console. Just that I dont get it back to the client. Any help ?
You should start by setting up a server to serve requests. I use expressjs for this - http://expressjs.com/
This will allow you to run nodejs as a web application.
Setup a route in express JS to serve your data - http://expressjs.com/api.html#express
var express = require('express');
var app = express();
app.get('/data', function(req, res){
res.send('hello world'); //replace with your data here
});
app.listen(3000);
Open up a browser, and type in http://MY_SERVER_ADDR:3000/data and you should see your output there.
Next, you'll need to attach an event handler to your HTML file that will trigger a $.get() request when it is triggered. Add the previous url to your data in your $.get call and do something with it.
$('.my_selector').click(function(){
$.get('http://MY_SERVER_ADDR:3000/data', {}, function(data){
console.log(data)
});
});
That should get you going.
After wrestling with the same question, i found that this is exactly where a template engine comes into the node-picture.
EJS solved it for me, but there are many more available.
This article compares 10 template engines.

Categories