Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Invoking an asynchronous method inside a middleware in node-http-proxy

I'm trying to create a proxy with node-http-proxy in Node.js that checks whether a request is authorized in a mongodb.

Basically, I created a middleware module for the node-http-proxy that I use like this:

httpProxy.createServer(
require('./example-middleware')(),
9005, 'localhost'
).listen(8005)

What the middleware module does is using mongojs to connect to mongodb and run a query to see if the user is authorized to access the resource:

module.exports = function(){
// Do something when first loaded!
console.log("Middleware loaded!");

return function (req, res, next) {
var record = extractCredentials(req);
var query = -- Db query --

//Debug:
log("Query result", query);

db.authList.find(query).sort({
    "url.len": -1
}, function(err, docs){
    console.log(docs);

    // Return the creator for the longest matching path:
    if(docs.length > 0) {
        console.log("User confirmed!");
        next();
    } else {
        console.log("User not confirmed!");
        res.writeHead(403, {
            'Content-Type': 'text/plain'
        });
        res.write('You are not allowed to access this resource...');
        res.end();
    }

});

}
}

Now the problem is that as soon as I add the asynchronous call to mongodb using mongojs the proxy hangs and never send the response back.

To clarify: on a "User not confirmed" everything works fine and the 403 is returned. On a "user confirmed" however I see the log but the browser then hangs forever and the request isn't proxied.

Now, if I remove the "user confirmed" and next() part outside of a callback it does work:

module.exports = function(){
// Do something when first loaded!
console.log("Middleware loaded!");

return function (req, res, next) {
    var record = extractCredentials(req);
    var query = --- query ---


    console.log("User confirmed!");
    next();
}

but I can't do that since the mongojs query is meant (rightfully I guess) to be executed asynchronously, the callback being triggered only when the db replied...

I also tried the version without using a middleware:

http.createServer(function (req, res) {
  // run the async query here!
  proxy.proxyRequest(req, res, {
  host: 'localhost',
  port: 9000
});
}).listen(8001);

But that did not help either...

Any clue? Note that I'm new to node.js so I suspect a misunderstanding on my side...

like image 780
domguinard Avatar asked Jul 26 '12 15:07

domguinard


People also ask

What is async/await in Node JS?

With support for asynchronous functions (often referred to as async/await) in Node.js as of v7.6, we can now extract data directly from a resolved Promise in an async middleware function and pass that data to the final router callback in a clean and easily-readable manner.

Why use async/await in express middleware?

By rewriting these features into middleware functions, I aim to simplify the writing of new router paths/API endpoints and hopefully increase code reusability. In closing, utilizing async / await as your Express middleware implementation helps keep your code reusable, readable, and up-to-date with current coding conventions.

What are the different patterns of asynchronous functions?

There are three patterns of asynchronous: 1. Callbacks: A callback function is a function passed into another function as an argument, which is then invoked inside the outer function to complete some kind of routine or action. This function is called when the asynchronous operation is completed.

Why should a code in Node JS be nonblocking?

Since the node is a language that runs on a single thread which in turn uses multiple threads in the background. A code in node.js should be nonblocking because if a particular line of code, for ex: Reading a large document can halt the execution of all the lines of code ahead of it which is not a good practice.


1 Answers

Found the answer, actually the catch is that the request needs to be buffered:

httpProxy.createServer(function (req, res, proxy) {
// ignore favicon
if (req.url === '/favicon.ico') {
    res.writeHead(200, {
        'Content-Type': 'image/x-icon'
    } );
    res.end();
    console.log('favicon requested');
    return;
}

var credentials = extractCredentials(req);
console.log(credentials);

var buffer = httpProxy.buffer(req);

checkRequest(credentials, function(user){
    if(user == ...) {
        console.log("Access granted!");
        proxy.proxyRequest(req, res, {
            host: 'localhost',
            port: 9005, 
            buffer: buffer
        });
    } else {
        console.log("Access denied!");
        res.writeHead(403, {
            "Content-Type": "text/plain"
        });
        res.write("You are not allowed to access this resource...");
        res.end();
    }

});

}).listen(8005);
like image 136
domguinard Avatar answered Oct 15 '22 10:10

domguinard