Nodejs - Express res.download giving Can't set headers after they are sent exception - javascript

I want to make an api that will serve files of any extensions.
Like this: http://localhost/download/[file].[extension]
Here is my code, but it is intermittently giving this message: Can't set headers after they are sent.
var express = require('express');
var app = express();
app.get('/download/:fileName/:extension', function(req, res){
var file = __dirname + '/' + req.params.fileName + '.' + req.params.extension;
res.download(file, function(err){
if (err) {
res.sendStatus(404);
}
res.end();
});
});
var server = app.listen(3000, function () {
var host = server.address().address;
var port = server.address().port;
console.log('app listening at http://%s:%s', host, port);
});

res.download has already sent a response (Not always true in the case of an error though)
You can fix this by doing
res.download(file, function(err){
if(err) {
// Check if headers have been sent
if(res.headersSent) {
// You may want to log something here or do something else
} else {
return res.sendStatus(SOME_ERR); // 404, maybe 500 depending on err
}
}
// Don't need res.end() here since already sent
}
Other changes called out in the comments above:
download uses sendFile, which you don't need res.end() after
download's documentation warns that you need to check res.headersSent when handling errors, as the headers may already be sent, which would mean you can't change the status

Related

How to make request to static resource with parameters?

I have my node.js restify server, and folder with static resource
const restify = require('restify')
let server = restify.createServer()
server.listen(8080, function () {
console.log('%s listening at %s', server.name, server.url)
});
server.get('/*', restify.plugins.serveStatic({
directory: __dirname + '/static',
default: 'index.html'
}));
i'm trying to understand how to make get request to index.html with parameters like localhost:8080/index.html?token=123
and if token is valid, return index.html to client, else return error
You can chain multiple request handlers and the next() method - first do some parameters' validation and then, as a second handler, use the serveStatic method. Here's an example:
const restify = require('restify')
let server = restify.createServer()
server.listen(8080, function () {
console.log('%s listening at %s', server.name, server.url)
});
server.get('/*', (request, response, next) => {
const token = request.query.token;
if(token !== '123') {
//those two lines below will stop your chain and just return 400 HTTP code with some message in JSON
response.send(400, {message: "Wrong token"});
next(false);
return;
}
next(); //this will jump to the second handler and serve your static file
return;
},
restify.plugins.serveStatic({
directory: __dirname + '/static',
default: 'index.html'
}));

How to store email in variables and send it with node.js

const functions = require('firebase-functions');
var nodemailer = require('nodemailer');
var transporter=nodemailer.createTransport('smtps://username#gmail.com:password#smtp.gmail.com');
exports.sendMail=functions.https.onRequest((req,res)=>{
var mailOptions={
to: 'sender#gmail.com',
subject: 'Test Mail',
html: 'Testing with Node.js'
}
transporter.sendMail(mailOptions,function(err,response){
if(err)
{
res.send('Mail not sent');
console.log(err);
}
else{
res.send('Mail sent');
}
});
});
I want to send email to various persons over time. I want to change the to: address in this code dynamically. So how to get a particular(sendermailid) variable from another javascript file and send to that person. My folders are located as below the picture.
How to get the variable from assmt.js to index.js(cloud function js).
You need to set up an express server who is listening our other JS aplication like this :
var express = require('express');
var app = express();
Now you can listen from another app on specified port :
var port = process.env.PORT || 8080;
app.listen(port);
console.log("App listening on port " + port);
Finally you have to intercept http post request to send your mail and get user info from the request :
app.post('/api/sendmail', function(req, res) {
var mail = {
from: req.body.user.emailFrom,
to: req.body.user.emailTo,
subject: "your subject",
html: "<p>email body</p>"
}
transporter.sendMail(mail, function(error, response){
if(error){
console.log("Error!");
console.log(error);
res.send(JSON.stringify(error));
}else{
res.send(JSON.stringify(response));
console.log("Success!")
transporter.close();
}
}
Your server is now ready you can start it with :
node serverName.js
And in your other js file ( assmt.js ) you send the http request with parameter :
send(user : User) {
let body = {user};
this.httpClient.post('http://localhost:8080/api/sendconge', body)
.subscribe(function(data) {
console.log(data);
});
}

How to do whitelist of IP's in Express?

I need to block every IP address from accessing my site except one or two IP's provided by myself. I have tried many modules but nothing seems to work.
var express = require('express')
var AccessControl = require('express-ip-access-control');
var app = express()
app.get('/', function (req, res) {
res.send('Hello World!')
})
var middleware = AccessControl(options);
app.use(AccessControl(options));
var options = {
mode: 'deny',
denys: [],
allows: ['**8.1**.1.**'],
forceConnectionAddress: false,
log: function(clientIp, access) {
console.log(clientIp + (access ? ' accessed.' : ' denied.'));
},
statusCode: 401,
redirectTo: '',
message: 'Unauthorized'
};
app.listen(3000, function () {
console.log(' app listening on port 3000!')
})
on running and accessing my site from my above code i am getting the console message as
::ffff:127.0.0.1 accessed.
::ffff:127.0.0.1 accessed.
::ffff:127.0.0.1 accessed.
::ffff:127.0.0.1 accessed.
any help?
You can simply add your own middleware that checks the IPs, no need to include another module.
You can see the ip from the request with req.connection.remoteAddress.
Before you define your routes, add something like this:
// Custom Middleware
app.use((req, res, next) => {
let validIps = ['::12', '127.0.0.1']; // Put your IP whitelist in this array
if(validIps.includes(req.connection.remoteAddress)){
// IP is ok, so go on
console.log("IP ok");
next();
}
else{
// Invalid ip
console.log("Bad IP: " + req.connection.remoteAddress);
const err = new Error("Bad IP: " + req.connection.remoteAddress);
next(err);
}
})
This will throw an error if an invalid ip comes in. Below all your routes, add something like this:
// Error handler
app.use((err, req, res, next) => {
console.log('Error handler', err);
res.status(err.status || 500);
res.send("Something broke");
});
You need to define your options before you use them. Otherwise, you're passing in undefined to app.use(AccessControl(options)).
Not sure how this is compiling for you, but adding the following line to the top of your script might help show a few more errors that would help.
'use strict';
Secondly, according to the express-ip-access-control documentation:
'allow' mode (Whilelist):
Deny by default, only allow IPs in the whitelist (allows) and not excluded by the blacklist (denys).
So change options.mode from 'deny' to 'allow'.

Cannot GET / DELETE Express.js

I have this script with which I'm trying to POST, GET and DELETE some stuff.
When I try POST or GET, the right messages are logged, but when I try DELETE, I get the following error:
Cannot GET /del_user
The URL I'm using is http://127.0.0.1:8081/del_user
What can be wrong in here?
var express = require('express');
var app = express();
// This responds with "Hello World" on the homepage
app.get('/', function (req, res) {
console.log("Got a GET request for the homepage");
res.send('Hello GET');
})
// This responds a POST request for the homepage
app.post('/', function (req, res) {
console.log("Got a POST request for the homepage");
res.send('Hello POST');
})
// This responds a DELETE request for the /del_user page.
app.delete('/del_user', function (req, res) {
console.log("Got a DELETE request for /del_user");
res.send('Hello DELETE');
})
// This responds a GET request for the /list_user page.
app.get('/list_user', function (req, res) {
console.log("Got a GET request for /list_user");
res.send('Page Listing');
})
// This responds a GET request for abcd, abxcd, ab123cd, and so on
app.get('/ab*cd', function(req, res) {
console.log("Got a GET request for /ab*cd");
res.send('Page Pattern Match');
})
var server = app.listen(8081, function () {
var host = server.address().address
var port = server.address().port
console.log("Example app listening at http://%s:%s", host, port)
})
I solved it by changing the app.delete to app.get and then placing the required remove statement inside the app.get. Something like this :-
app.get('/delete/:userId', (req, res) => {
Users.remove({ _id: req.params.userId }, (error, posts) => {
if (error) {
console.warn(error);
}
else {
data = posts
res.render("delete", {"data": data})
}
});
});
In your code you're binding the /del_user URL to the HTTP DELETE method.
So all you need to do is specify the DELETE method in your application or in Postman.
If you're not using it, it's an App in Google Chrome and you might want to download it, it makes your life a LOT easier ;)
Also, since the HTTP method is already declared to be DELETE, there is no need to specify it in the URL.
This is part of the RESTful working.
If you are using AJAX to try your code, you need to specify the method, which is delete.
$.ajax({
url: "http://127.0.0.1:8081/del_user",
type: "DELETE"
});

Capturing Cookies (req.headers.cookie) on homepage with Express on node

I am doing a basic authentication example. I have Node, Express, and Cookie. I make and store a cookie once the user logs in. Upon refreshing the page, I want to use the cookie to show that the user is still logged in on the response, and provide the information related to that user.
Server side:
// If I put the app.get('/'.....) up here I get the response, but not the page HTML/JS/CSS/etc...
// This uses the /app as the root directory
app.use(express.static(__dirname + '/app'));
// Here I get the page HTML/JS/CSS/etc but can't capture the cookie
app.get('/', function(req, res) {
console.log('I want to get here');
if(req.headers.cookie){
// This parses the cookies into a usable array
var incoming_cookies = cookie.parse(req.headers.cookie);
Person.find({...})
.then( function(results) {
if (weDontFindSomeone) {
console.log('user not found');
res.status(400).send('user not found');
} else {
if (incoming_cookies.uname === loggedIn.uname) {
console.log('Starting with a cookie logged in');
res.status(200).send(results);
} else {
console.log('Some other problem with cookies');
res.status(400).send('Some other problem with cookies');
}
}
})
.catch(function(error){
res.status(400).send('some other error in starting, error: ' + error);
});
} else {
res.status(200).send('Starting from scratch.');
}
});
How do I capture the cookies on the request to the homepage and use that to determine what is served to the client?
Do I put it in the JS on the client side?
If you want to suggest another node module, PLEASE show a working example in a plkr, fiddle, web page example, or the like. I do better studying working code, as it has taken me a bit long to get to this pont :)
Setting the cookie, also on the server side:
app.post('/api/login', function (req, res) {
console.log('Getting a login request');
if (weValidateTheCredentials) {
Person.find({...})
.then(function(personResults) {
if (personResults.rowCount === 0) {
res.status(400).send('user not found');
} else {
console.log('Logging in at \'/api/login\', and sending a cookie.');
// 3 hours max age
res.cookie('UID', req.body.uid, {maxAge: 10800000});
res.cookie('uname', req.body.uname, {maxAge: 10800000});
res.status(200).send(personResults);
}
})
.catch(function(error){
res.status(400).send('some other error in logging in, error: ' + error);
});
} else {
res.status(400).send('login requires a uname and pwhash');
}
});
The method with Cookie is a bit devious, you can use cookie-parser, It's made for express.
It is really simple, there is a example on the home page:
var express = require('express')
var cookieParser = require('cookie-parser')
var app = express()
app.use(cookieParser())
app.get('/', function(req, res) {
console.log("Cookies: ", req.cookies)
})
app.listen(8080)
// curl command that sends an HTTP request with two cookies
// curl http://127.0.0.1:8080 --cookie "Cho=Kim;Greet=Hello"
Or with your code:
var cookieParser = require('cookie-parser');
// Add cookie parser
app.use(cookieParser());
app.get('/', function(req, res) {
console.log('I want to get here');
if(req.cookies){
Person.find({...})
.then( function(results) {
if (weDontFindSomeone) {
console.log('user not found');
res.status(400).send('user not found');
} else {
if (req.cookies.uname === loggedIn.uname) {
console.log('Starting with a cookie logged in');
res.status(200).send(results);
} else {
console.log('Some other problem with cookies');
res.status(400).send('Some other problem with cookies');
}
}
})
.catch(function(error){
res.status(400).send('some other error in starting, error: ' + error);
});
} else {
res.status(200).send('Starting from scratch.');
}
});
// This uses the /app as the root directory
app.use(express.static(__dirname + '/app'));
I was mixing the paradigm of what should be handled by the server and what should be handled by the client.
Using Jquery addon 'jquery-cookie-master', I can check the cookie on the request of the client side with if ($.cookie('attributeWanted')){...}

Categories