hguser
hguser

Reputation: 36028

Send the request to next event handler in NodeJS

I am trying to create a module which can log some certain params for the request and print them to the page which can be checked online, the page will use the socket.io to load the latest logs.

And I want this module can worked as a plugin which means you just call this module, and initialize it, then an extra entry point /_logger will be added to you application, once you visit the page, the latest logs will be updated in real-time. So the module have to intercept the requests:

function setup(httpServer) {
    //page
    httpServer.on("request", function (request, response) {
        var pathname = url.parse(request.url).pathname;
        if (pathname === '/_logger') {
            fs.readFile(__dirname + '/logger.html', (err, data) => {
                response.writeHead(200, { 'Content-Type': 'text/html' });
                response.write(data);
                response.end();
            });
        }else{
          // how to give up the control for this requset
        }
    });


    var io = require('socket.io')(httpServer);
    io.on('connection', function (socket) {
        //TO BE DONE
        socket.on('event', function (data) { });
        socket.on('disconnect', function () { });
    });
}
module.exports = {
    setup: setup
}

Usage:

var logger= require("./logger/index");
var server = require('http').createServer();
logger.setup(server);
server.on("request", function(req,res){
  //Normal logic for different application
});
server.listen(3333);

Now the problem is that once the requested url is not /_logger, I should release the control of this request.

        if (pathname === '/_logger') {
          //take control
        }else{
          // Nothing should be done here, it should go to the next request chain.
        }

After read the documents, I can not find the right way to make it.

Any ideas?

Upvotes: 0

Views: 1639

Answers (2)

zeronone
zeronone

Reputation: 3041

Assuming that you want to use low-level NodeJS HTTP API. You can compose several handlers into one handler using function composition. Each handler should yield the execution to the next handler, if the req.url doesn't matches.

var http = require('http');

var handler1 = function(req, res) {
    res.writeHead(200, { 'Content-Type': 'text/html' });
    res.write('/');
    res.end();  
}

var handler2 = function(req, res) {
    res.writeHead(200, { 'Content-Type': 'text/html' });
    res.write('/Hello');
    res.end();  
}

var middleware = compose([wrapHandler('/', handler1),
                         wrapHandler('/hello', handler2)]);

http.createServer(middleware).listen(3000);

function wrapHandler(path, cb) {
    return function (req, res, next) {
        if (req.url === path) {
            cb(req, res);
        } else {
            next();
        }
    };
}

function notFoundHandler(req, res) {
    res.writeHead(404, { 'Content-Type': 'text/html' });
    res.write('No Path found');
    res.end();    
};

// adapted from koa-compose
function compose(middleware) {
    return function (req, res){
        let next = function () {
            notFoundHandler.call(this, req, res);
        };

        let i = middleware.length;
        while (i--) {
            let thisMiddleware = middleware[i];
            let nextMiddleware = next;
            next = function () { 
                thisMiddleware.call(this, req, res, nextMiddleware);
            }
        }
        return next();
    }
}

In your case, you can write.

var loggerHandler = wrapHandler('/_logger', logger.handler);
httpServer.on('request', compose(loggerHandler, handler2, handler3));

Upvotes: 2

jfriend00
jfriend00

Reputation: 707396

httpServer.on("request", ...) is just one request listener. It is under no obligation to process the request if it doesn't need to. Even if it does nothing, any other request listeners will still get notified of this request.

If there are other request listeners (which you are implying that there are), then you can just do nothing in the request listener you show and the other listeners will also get a shot at the particular request. This allows you to add your own request listener to a working http server and your listener only has to pay attention to the new route that it wants to support and can just ignore all the other routes and they will get handled by the other listeners that are already in place.


Now, there are frameworks built to make this both simpler and to give you more control. In general, these frameworks use one listener and they provide a means for you to handle the request OR explicitly tell the framework that you have not handled the request and would like other route handlers to have a shot at handling the request. This is a bit more flexible than just have multiple listeners, all of which will get notified of the same route.

For example, using the Express framework, you can do this:

var express = require('express');
var app = express();

// route handler for / request only when a user=xxx is in the query string
app.get('/', function(req, res, next) {
    // if user was included in query parameter
    if (req.query.user) {
        // do something specific when ?user=xxxx is included in the URL
    } else {
        // pass handling to the next request handler in the chain
        next();
    }
});

// route handler for / request that wasn't already handled
app.get('/', function(req, res) {
    // handle the / route here
});

app.listen(80);

Upvotes: 1

Related Questions