在NodeJS Express中删除路由映射

24

我有一个映射为:

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

我如何在运行时删除/重映射该路由到一个空处理程序?

8个回答

35

这将删除app.use中间件和/或app.VERB(get/post)路由。在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);
}

请注意,这要求中间件/路由函数必须有名称。
app.use(function yourMiddlewareFunctionName(req, res, next) {
    ...          ^ named function
});

如果函数是匿名的,则不起作用

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

8
在上述代码中,route.path 包含路径名称 - 如果您想通过路径删除匿名路由,则可以使用该选项。 - Jesse
route.path 在我的情况下未定义,但 route.route.path 具有正确的值。 - Tofandel

26

Express(至少从3.0.5开始)将所有路由存储在app.routes中。 根据文档的描述:

app.routes对象包含所有按相关HTTP动词定义的路由映射。 此对象可用于内省功能,例如Express不仅在路由中使用它,而且还提供默认的OPTIONS行为,除非使用app.options()。 您的应用程序或框架也可以通过从此对象中删除路由来移除路由。

您的app.routes应该类似于这样:

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

所以,您应该能够循环遍历app.routes.get,直到找到您要查找的内容,然后将其删除。


这非常有帮助。但是,当我不断尝试时,我遇到了非常奇怪的问题。您是否可以以任何方式编写一个简单的示例? - streetlight
特别是,它还删除了我所有的静态资源映射 -- 你知道这是为什么吗?这是我的问题,其中包含更多详细信息... http://stackoverflow.com/questions/15487084/removing-a-specfic-mapped-route-in-node-js-at-runtime-removes-static-mapping - streetlight
1
express@4.9.5版本开始已经不再是这样了。请查看我的答案 - laggingreflex

9
上述方法需要您为路由拥有一个命名函数。我也想这样做,但是我没有为路由编写命名函数,所以我编写了一个npm模块,可以通过指定路由路径来删除路由。
以下是内容:

以上方法需要您为路由拥有一个命名函数。我也想这样做,但是我没有为路由编写命名函数,所以我编写了一个npm模块,可以通过指定路由路径来删除路由。

给你:

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


4

在服务器运行时,可以删除已添加的处理程序(使用app.use),尽管没有API可供使用,因此不建议这样做。

/* 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;
}

这是我需要的内容,可惜没有一个合适的API,但是Express在这里只是模仿Connect的做法。


4
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);

当你访问 http://...awesome 时,fn2 将被调用 :)

编辑:修复了代码

编辑2:再次修复...

编辑3:也许更简单的解决方案是在某个时间点清除路由并重新填充它们:

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

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

3

一旦路由被建立,我似乎无法修改现有的路由,包括添加新的中间件。虽然目前我将使用next('route')命令。 - lostinplace

3

如上所述,新的Express API似乎不支持此功能。

  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.


我的使用场景是允许用户在CMS(基于浏览器的前端应用程序)中配置路由。此外,我还想根据标题信息(如 Host 字段)对这些路由进行范围限定。我可能会将所有请求都路由到同一个处理程序,然后在 Express 路由 API 之外进行自定义路由处理。 - Brennan Cheung

0

没有官方方法,但您可以使用stack来实现。

function DeleteUserRouter(appName){

router.stack = router.stack.filter((route)=>{
  if(route.route.path == `/${appName}`){
     return false;
  }
  return true;
});
}

appName 是路径名。

在 router.route.stack 中过滤方法,其中 router 是 express.Router,或者您可以对 app 进行相同操作,但使用 app._router.stack。

注意:对于 4.0 以下版本,请使用 app.router.stack。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接