Nodejs Express 有个 router.use(),有木有方法实现类似 router.unuse()来撤销router.use?

Nodejs Express 有个 router.use(),有木有方法实现类似 router.unuse()来撤销router.use?

在Express 4.x 中,通过router.use可以使用router级别的中间件,通过什么方式可以实现类似 router.unuse 的功能,来取消使用这个中间件。

这个过程都是在系统运行时进行的,答案不能是删掉相关代码重启应用哟。

6 回复

在Express.js中,并没有直接提供router.unuse()这样的方法来撤销已经注册的中间件。但是,我们可以通过一些技巧来实现类似的功能。下面是一个简单的示例代码,展示如何实现一个类似于router.unuse()的功能。

示例代码

首先,我们需要创建一个自定义的方法来管理中间件的注册和撤销:

const express = require('express');
const app = express();
const router = express.Router();

// 存储已注册的中间件
const registeredMiddleware = [];

// 自定义的 use 方法
router.customUse = function (middleware) {
    // 注册中间件
    router.use(middleware);
    // 记录已注册的中间件
    registeredMiddleware.push(middleware);
};

// 自定义的 unuse 方法
router.customUnuse = function (middleware) {
    // 查找并移除指定的中间件
    const index = registeredMiddleware.indexOf(middleware);
    if (index !== -1) {
        // 移除已注册的中间件
        registeredMiddleware.splice(index, 1);
        // 移除路由上的中间件
        router.stack = router.stack.filter(layer => layer.handle !== middleware);
    }
};

// 示例中间件
const myMiddleware = (req, res, next) => {
    console.log("Hello from myMiddleware");
    next();
};

// 使用自定义的 customUse 方法注册中间件
router.customUse(myMiddleware);

// 使用自定义的 customUnuse 方法撤销中间件
router.customUnuse(myMiddleware);

app.use('/api', router);

app.listen(3000, () => {
    console.log('Server is running on port 3000');
});

解释

  1. 自定义的 customUse 方法:

    • 这个方法与router.use()类似,但会将注册的中间件存储在一个数组中。
  2. 自定义的 customUnuse 方法:

    • 这个方法接受一个中间件作为参数,并从存储的数组中查找并移除它。
    • 然后,它还会从router.stack中移除相应的中间件层。

通过这种方式,你可以在运行时动态地添加和移除中间件,而无需重启应用。这在某些需要动态配置的应用场景中非常有用。


刚略了下express的代码,有一个可行的办法:

遍历 router.stack,找到router.stack[i].handle === 这个中间件的元素,删掉它就可以了。

不知道这样做有什么隐患,或者还有木有更好的方法。

proto.use = function(route, fn){ // default route to '/' if (‘string’ != typeof route) { fn = route; route = ‘/’; }

if (typeof fn !== ‘function’) { var type = {}.toString.call(fn); var msg = 'Router.use() requires callback functions but got a ’ + type; throw new Error(msg); }

// strip trailing slash if (’/’ == route[route.length - 1]) { route = route.slice(0, -1); }

var layer = new Layer(route, { sensitive: this.caseSensitive, strict: this.strict, end: false }, fn);

// add the middleware debug(‘use %s %s’, route || ‘/’, fn.name || ‘anonymous’);

this.stack.push(layer); return this; };

//this.stack.push(layer); 从router.stack 里面把LAYER删掉。可自写方法 EXPRESS/LIB/ROUTER/INDEX.JS

其实可以看一下源码,楼上也给出了,可以考虑自己发个merge request

当我执行 mysql.query(sql,callback); 的时候。。。

就很慢的刷新页面没有错误。。。但是在我不停的刷新页面的时候。。。。控制台就报错了。 错误提示如下图: err1.png

然后我去看了看 mysql错误提示的地方

err2.png

不知道为什么。。。只要快速刷新页面, 过一会就报错一下。然后我express.send 也跟着报错。好像是在send设置响应头部的时候,已经有内容输出了。 但是 我 console.log(mysql err); 完全没错误任何东西。不是null 。

下面是全部错误。 err3.png

在Express.js中,并没有内置的router.unuse()方法来撤销已经添加的中间件。不过,你可以通过维护一个中间件列表的方式来实现类似的功能。

实现思路

  1. 创建一个自定义的路由器类。
  2. 使用一个数组来存储所有已添加的中间件。
  3. 提供一个方法来移除指定的中间件。

示例代码

const express = require('express');

class CustomRouter extends express.Router {
  constructor(...args) {
    super(...args);
    this.middlewareList = [];
  }

  use(fn) {
    super.use(fn);
    this.middlewareList.push(fn);
  }

  unuse(fn) {
    const index = this.middlewareList.indexOf(fn);
    if (index !== -1) {
      this.middlewareList.splice(index, 1);
      // 重新创建路由,移除指定的中间件
      const newRouter = express.Router();
      this.stack.forEach(layer => {
        if (!layer.handle._name.includes('anonymous')) {  // 假设匿名函数不是我们需要移除的中间件
          newRouter.use(layer.handle);
        }
      });
      Object.assign(this, newRouter);
    }
  }
}

const app = express();
const customRouter = new CustomRouter();

customRouter.use((req, res, next) => {
  console.log('This is a middleware');
  next();
});

app.use('/api', customRouter);

// 使用unuse移除中间件
customRouter.unuse((req, res, next) => {
  console.log('This is a middleware');
  next();
});

app.listen(3000, () => {
  console.log('Server is running on port 3000');
});

解释

  • CustomRouter 类继承了 express.Router 类,并添加了一个 middlewareList 数组来记录所有已添加的中间件。
  • use 方法不仅调用父类的 use 方法添加中间件,还将中间件函数添加到 middlewareList 数组中。
  • unuse 方法遍历 middlewareList 数组,找到并移除指定的中间件。
  • 在移除中间件后,我们重新创建一个新的 Router 实例,并将未被移除的中间件添加到新实例中,然后替换当前实例。

这种方法虽然能实现所需的功能,但可能会影响性能,特别是在中间件数量较多的情况下。因此,在实际应用中,应谨慎使用。

回到顶部