I know that Array.forEach is synchronous.
But I've this code:
function middleware (req, res, next) {
Array.forEach(
Array.forEach(
if(true) { return next(); }
)
)
return res.send("false");
}
// next()
function isTrue (req, res) {
return res.send("true");
}
And every time I execute it, it sends two headers. First the isTrue function header, and later, the middleware function header.
I understand that if Array.forEach() is synchronous, it should be executed before res.send("false"). But it's not the behaviour. So there is something that I don't understand.
To answer the complete question we'd need to see your code, but to answer the very basic javascript question, the return inside forEach only returns from forEach and not from your outer middleware function. So everything within the middleware function is still executing after forEach.
Again, it's impossible to offer a real solution, but instead of forEach you'd typically use some for these kind of checks.
const ret = [1,2,3].some(e => e === '<yourCondition>');
res.send(ret);
Related
I'm working on a homemade RBAC system with Nodejs Express, based on two levels:
First, verify if the user has the right role to perform this action.
Second, verify if the user has the right plan to perform this action.
, I create a middleware like this:
exports.can = function (resource, action) {
return function (request, response, next) {
action = action || request.method;
if (!request.user) {
return next(new errors.UnauthorizedError());
}
request.user.can(request.user.role, request.user.currentPack, resource, action, function (can, error) {
if (error) return next(error);
if (!can) {
return next(new errors.UnauthorizedError());
}
return can;
});
return next();
};
};
I added to my User model this method:
const rbac = new RBAC(rbacJson);
const pack = new PACK(packJson);
schema.method('can', function (role, userPack, resource, action, next) {
let can = false;
action = action.toUpperCase();
can = rbac.can(role, resource, action);
if (can) {
can = pack.can(userPack, resource, action, function (can) {
return next(can);
});
}
return next(can);
});
In my method pack.can(...) I need to execute a mongoose query like this:
PACK.prototype.can = function (pack, resource, action, next) {
let can = true;
// some sequantial code
Trader.count({/* some conditions */}, function (err, count) {
if(count == 0) return next(true);
return next(false);
});
return can;
};
My problem is when the return of Mongoose query is next(false), I have this error:
Error: Can't set headers after they are sent.
at ServerResponse.OutgoingMessage.setHeader (_http_outgoing.js:356:11)
at ServerResponse.header (/home/invoice/node_modules/express/lib/response.js:730:10)
at ServerResponse.send (/home/invoice/node_modules/express/lib/response.js:170:12)
at ServerResponse.json (/home/invoice/node_modules/express/lib/response.js:256:15)
at ServerResponse.response.apiResponse (/home/invoice/server/config/middlewares/api.js:10:14)
at /home/invoice/server/controllers/api/invoice/traders.js:130:21
at /home/invoice/node_modules/mongoose/lib/model.js:3835:16
at /home/invoice/node_modules/mongoose/lib/services/model/applyHooks.js:162:20
at _combinedTickCallback (internal/process/next_tick.js:73:7)
at process._tickDomainCallback (internal/process/next_tick.js:128:9)
After an investigation, I found that the error is maybe due to the double callback Call:
can = pack.can(userPack, resource, action, function (can) {
return next(can);
});
return next(new errors.UnauthorizedError());
But I don't know how to solve this.
I hope that I well explained my problem.
So let's start with the error:
Can't set headers after they are sent.
Nine times out of ten this is caused by trying to send two responses to the same request. The reference to headers is a little misleading, though technically true. The first thing the second response will try to do is set some headers, which will fail because the first response has already sent them back to the client.
The stack trace gives you a clear indication of where the second response originates, including filenames and line numbers. More difficult is to track down the first response, generally I'd just throw in some extra console logging to figure it out.
In the question you mention that you believe you've found the source of the problem but it looks to me like it might just be the tip of the iceberg. You've repeatedly used the same pattern and even if you fix it in one place that may not be sufficient.
Before I get into that, let's start with this:
return next();
For the purposes of this example it doesn't really matter whether you pass an error, e.g. return next(err);, the point is the same. First it invokes next(), which returns undefined. It then returns undefined from the surrounding function. In other words, it's just a convenient shorthand for this:
next();
return;
The reason why we return is to ensure that nothing else happens after we've called next(), we always try to ensure that calling next() is the last thing we do in our handler, not least because otherwise we can have bugs where we try to send the response twice.
The (anti-)pattern you've used looks a bit like this:
obj.doSomething(function() {
return next(); // next 1
});
return next(); // next 2
Again, it doesn't really matter whether you're calling next() or next(err), it all works out much the same. The key thing to note is that the return for next 1 is just returning from the function passed to doSomething. It isn't doing anything to prevent next 2 from being hit. Both next 1 and next 2 will be called.
In places your code seems unclear about whether it's trying to be synchronous or asynchronous, using callbacks and return values at the same time. It makes it a little bit difficult to say for sure what the 'correct' code should look like. Specifically, is the value of can supposed to be returned synchronously or passed to the callback asynchronously? I suspect it's the latter but the current code seems torn between the two. It's important to ensure that you don't call next() until you're ready for the next thing to happen, so if you're waiting on a DB query you mustn't call next until that comes back.
Personally I'd rename your callbacks so they aren't all called next, I find that really confusing. When I see next I'm expecting it to be an Express next function, not just an arbitrary callback.
It's a bit of a guess but I'd suggest your middleware should look something like this:
exports.can = function (resource, action) {
return function (request, response, next) {
action = action || request.method;
if (!request.user) {
return next(new errors.UnauthorizedError());
}
request.user.can(request.user.role, request.user.currentPack, resource, action, function (can, error) {
if (error) {
next(error);
}
else if (can) {
next();
}
else {
next(new errors.UnauthorizedError());
}
});
// Do not call next() here
};
};
The relevant section of the User model would then be:
if (can) {
pack.can(userPack, resource, action, function (can) {
next(can);
});
}
else {
next(can);
}
If I want to avoid lots of else blocks and deep indentations, what should be the return type if I want to exit a router function explictly?
app.get("/xx", function(req, res) {
if (c1) {
res.render("c1");
return ??;
}
if (c2) {
res.render("c2");
return ??;
}
res.render("default");
})
It doesn't really matter. This is an asynchronous function, and nobody's going to use this return value, so you can just return undefined:
res.render(...);
return;
As it doesn't matter, you can also write:
return res.render(...);
But I think it looks more readable in two lines.
Instead of res.render() you should be using res.send(), as it will terminate the response stream with the output sent.
i want an expressjs middlware to be executed always.
That is even if there is an error in the next() or not.
is it possible?
example
app.get('/',[middle1,middle2],doIt)
the middle2 should always execute even if the middle1 executes next with error.
NOTE: the middle2 should always execute last and takes the values calculated by the previous middlewares. also there are lot of middlewares between middle1 and middle2.
If middle1 is known to not use any async operations from which it calls next(), then you can wrap it and put a try/catch around it so that if it throws, you can just call next() on its behalf.
If it does use async operations or you don't know if it will use async operations, then you will only catch its exceptions if it throws synchronously (before it goes async) and you will not be able to catch any exceptions that it throws asynchronously. About the best you could do for async behavior is to set some sort of timeout in your wrapper. If it hasn't called next() within some period of time (either because it threw an exception or just failed in some other weay), then you call next after the timeout period.
Wrapping a non-async middle1 could look like this:
function wrap(fn) {
return function(req, res, next) {
var nextCalled = false;
try {
fn(req, res, function() {
nextCalled = true;
next();
});
} finally {
if (!nextCalled) {
next();
}
}
}
}
app.get('/',[wrap(middle1),middle2],doIt);
The wrap() function inserts a stub as the middleware function. That stud inserts its own next() function so it can tell if the actual middleware function calls next() or not. It then wraps an exception handler around the middleware function so if it throws an exception synchronously, then it can recover. After the function returns, it checks to see if next() was called and, if not, it calls it.
As explained earlier this approach only works if the middleware function is synchronous.
Assuming you do not care about the order of execution, you can simply have function middle2 execute inside app.use.
app.use(middle2);
app.get('/pathx, middle1, middle3, doIt);
middle2 will always be executed on every request. However, middle2 will execute before any of the other middleware
If you require middle2 to execute last in sequence, then a simple modification using the async module should accomplish what you want
async = require('async');
function middleware(req, res, next){
var functionList = [middle1, middle3];
async.series(functionList, function(err, results){
if(err){
middle2(req, res, next);
next(err);
}
middle2(req, res, next);
next();
}
}
app.get('/pathX', middleware, doIt);
I'm using the node-soap client from milewise (create API by the way), but I have some difficulties to get the results of the callback to the right scope.
Here is the code I have for now:
function generateSoapRequest(req, res, next)
{
soap.createClient('http://127.0.0.1:' + cfg.service_port + cfg.service_url_path,
function(err, client) {
client.CXIf.CXIf.CXProcessXML(
{"XMLRequestData": {"CXLogon": {"UserID":"1901007", "Password":"2580", "LogonType":11 } } },
function(err, result, body) {
if (err) {
console.log(err);
return;
}
console.log(result);
var cxresponse = result.XMLResponse[0].CXResponse;
console.log('SessionID:' + cxresponse.SessionID + ' SessionInstanceID:' + cxresponse.SessionInstanceID);
});
});
}
function getVoiceMailInformation(req, res, next) {
var cxresponse = generateSoapRequest(req, res, next);
var something = doSomethingNext(cxresponse);
}
function doSomethingNext(cxresponse){....; return something;}
Basically, when I launch the getVoiceMailInformation(), it creates a soap client and request some information through the generateSoapRequest().
The next step would be to get the result of that function (not implemented in the code above, because I don't know how) and do something else.
My problem is soap.createClient is asynchronous, so the callback is fired well after the function is complete.
What would be the best approach ?
(Maybe it's something trivial, but the scope of an anonymous function in javascript is something that is killing me.)
Any help will be very appreciated.
Basically you can't do something like:
var cxresponse = generateSoapRequest(req, res, next);
because the function you're calling invokes asynchronous code, and therefore can't return a value that's determined by that code. The normal way around this is to give the function an extra callback parameter for a function that will be called with the result once the result becomes available. It doesn't have to be an anonymous function; it can be a named function. In your case, (assuming you've modified generateSoapRequest to take a callback as its fourth argument and call it when the results are ready, you could write
generateSoapRequest(req, res, next, doSomethingNext);
and then doSomethingNext will be called with cxresponse as an argument. Of course, since doSomethingNext also gets called asynchronously, it can't return a value either, so you'll have to apply the same technique to it.
The async module can make this sort of thing easier: in particular, its "waterfall" pattern is useful when you have a bunch of functions that have to run in sequence, each being called back from the previous one.
I am learning Node.js, and I have read some tutorials, like The Node Beginner Book for learning the core funcionality. But the more I read some examples, the more doubts I start collecting.
On the further example, obtained from a tutorial, we can see that for a CRUD 'read' request for key /documents/titles.json, we are returning a value:
app.get('/documents/titles.json', loadUser, function(req, res) {
Document.find({ user_id: req.currentUser.id },[], { sort: ['title', 'descending'] },
function(err, documents) {
res.send(documents.map(function(d) {
return { title: d.title, id: d._id };
}));
});
});
On this example, the function loaduser() is used for authentication purposes:
function loadUser(req, res, next) {
if (req.session.user_id) {
User.findById(req.session.user_id, function(err, user) {
if (user) {
req.currentUser = user;
next();
} else {
res.redirect('/sessions/new');
}
});
}
}
What I don't understand is:
I suppose that node.js, before start executing the app.get, it goes to loaduser function. loadUser() function has three parameters: req,res,next, but I don't see, at least, how you pass from app.get() the "req" parameter to loadUser(). From where does it come?
Inside loadUser() function, when you execute next(), it means that the function app.get()" can continue its procedure, but this req.currentUser = user, is the same req that is used on app.get() function?
Inside loadUser() function, when you execute res.redirect() code, automatically breaks the procedure on app.get() function, right? it looks like it doesn't return to Document.find().
The questions you've asked are about the Express framework internals specifically:
When you call app.get(route, loadUser, final) Express will make a stack (array) with the loadUser and final function functions and it will know that when you call next it should execute the following function in the stack with the same req and res params.
When you call next it will just pass to the next function in the middleware stack.
Since you call res.redirect and you don't call return, it won't pass to the next function in the stack (the one with Document.find).
Resources:
http://howtonode.org/getting-started-with-express
I think in order to be comfortable with this you need get familiar with idea of middleware and how it's used in connect framework.
I've found few articles where this subject explained well enough. Take a look there:
http://howtonode.org/connect-it
and here http://stephensugden.com/middleware_guide/
the main idea is you have a set of layers and each time when new request arrives it goes through each level and on each level you can decide what to do with that. You can stop at some level, do something and return response or you can pass it to the next layer