简体   繁体   中英

Remove route mappings in NodeJS Express

I have a route mapped as:

app.get('/health/*', function(req, res){
    res.send('1');
});

How can I remove / remap this route to an empty handler at runtime?

This removes app.use middlewares and/or app.VERB (get/post) routes. Tested on express@4.9.5

var routes = app._router.stack;
routes.forEach(removeMiddlewares);
function removeMiddlewares(route, i, routes) {
    switch (route.handle.name) {
        case 'yourMiddlewareFunctionName':
        case 'yourRouteFunctionName':
            routes.splice(i, 1);
    }
    if (route.route)
        route.route.stack.forEach(removeMiddlewares);
}

Note that it requires that the middleware/route functions have names :

app.use(function yourMiddlewareFunctionName(req, res, next) {
    ...          ^ named function
});

It won't work if the function is anonymous:

app.get('/path', function(req, res, next) {
    ...          ^ anonymous function, won't work                    
});

Express (at least as of 3.0.5) keeps all of its routes in app.routes . From the documentation :

The app.routes object houses all of the routes defined mapped by the associated HTTP verb. This object may be used for introspection capabilities, for example Express uses this internally not only for routing but to provide default OPTIONS behaviour unless app.options() is used. Your application or framework may also remove routes by simply by removing them from this object.

Your app.routes should look similar to this:

{ get: 
   [ { path: '/health/*',
       method: 'get',
       callbacks: [Object],
       keys: []}]
}

So, you should be able to loop through app.routes.get until you find what you are looking for, and then delete it.

It is possible to remove mounted handlers (added with app.use) while the server is running, although there is no API to do this, so it isn't recommended.

/* Monkey patch express to support removal of routes */
require('express').HTTPServer.prototype.unmount = function (route) {
    for (var i = 0, len = this.stack.length; i < len; ++i) {
        if (this.stack[i].route == route) {
            this.stack.splice(i, 1);
            return true;
        };
    }
    return false;
}

This is something I need, so it's a shame there isn't a proper api, but express is just mimicing what connect does here.

app.get$ = function(route, callback){
  var k, new_map;

  // delete unwanted routes
  for (k in app._router.map.get) {
    if (app._router.map.get[k].path + "" === route + "") {
      delete app._router.map.get[k];
    }
  }

  // remove undefined elements
  new_map = [];
  for (k in app._router.map.get) {
    if (typeof app._router.map.get[k] !== 'undefined') {
      new_map.push(app._router.map.get[k]);
    }
  }
  app._router.map.get = new_map;

  // register route
  app.get(route, callback);
};

app.get$(/awesome/, fn1);
app.get$(/awesome/, fn2);

And then when you go to http://...awesome fn2 will be called :)

Edit: fixed the code

Edit2: fixed again...

Edit3: Maybe simpler solution is to purge routes at some point and repopulate them:

// remove routes
delete app._router.map.get;
app._router.map.get = [];

// repopulate
app.get(/path/, function(req,res)
{
    ...
});

The above approach requires you have a named function for the route. I wanted to do this as well but didn't have named functions for routes so I wrote an npm module that can remove routes by specifying the routing path.

Here you go:

https://www.npmjs.com/package/express-remove-route

您可以查看Express 路由中间件并可能进行重定向。

As already mentioned above, the new Express API doesn't seem to support this.

  1. Is it really necessary to completely remove the mapping? If all you need is to stop serving a route, you can easily just start returning some error from the handler.

    The only (very odd) case where this wouldn't be good enough is if dynamic routes were added all the time, and you wanted to completely get rid of old ones to avoid accumulating too many...

  2. If you want to remap it (either to do something else, or to map it to something that always returns an error), you can always add another level of indirection:

     var healthHandler = function(req, res, next) { // do something }; app.get('/health/*', function(req, res, next) { healthHandler(req, res, next); }); // later somewhere: healthHandler = function(req, res, next) { // do something else }; 

    In my opinion this is nicer/safer than manipulating some undocumented internals in Express.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM