简体   繁体   English

Express.js - 将每个中间件/路由包装在“装饰器”中

[英]Express.js - wrap every middleware/route in "decorator"

I have Express.js instance and couple of routes which I want to wrap in some function.我有 Express.js 实例和几条路线,我想将它们包装在一些 function 中。 Example:例子:

const wrapper = (route) => {
  return (req, res, next) => {
    let result = route(req, res, next);

    // do some independent processing
  }
};

app.get('/', wrapper((req, res, next) => {
  // respond to request somehow
}));

While this works fine, I don't like the idea to explicitly call wrapper on every route or middleware which requires such processing.虽然这很好用,但我不喜欢在需要此类处理的每个路由或中间件上显式调用wrapper的想法。

Is there any way to be able to wrap every required route/middleware in certain wrapper (given that wrapper function can check that this route/middleware needs to be wrapped) implicitly (via Express.js extension, monkey-patching or some special middleware)?有什么方法可以将每个所需的路由/中间件包装在某个包装器中(假设wrapper function 可以检查此路由/中间件是否需要包装)隐式(通过Express.js扩展、猴子补丁或一些特殊的中间件) ?

UPDATE:更新:

More solid example.更扎实的例子。 Let's assume I want to make an async router functions.假设我想创建一个async路由器功能。 But I don't want to catch errors in each and every route function.但我不想在每条路线 function 中发现错误。 So I wrap them up:所以我把它们包起来:

const wrapper = func => (req, res, next) => {
  const promise = func(req, res, next);

  if (promise.catch) {
    promise.catch(err => next(err));
  }

  next();
};

app.get('/one', wrapper(async (req, res, next) => {
  // respond to request somehow
}));

app.get('/two', wrapper(async (req, res, next) => {
  // respond to request somehow
}));

app.get('/three', wrapper(async (req, res, next) => {
  // respond to request somehow
}));

// and so on...

app.use((err, req, res, next) => {
  // do something with intercepted error
});

This explicit wrapper around all routes is actually the thing I want to get rid of.这个围绕所有路由的显式wrapper实际上是我想要摆脱的东西。

It turned out to be a bit of a PITA because, ultimately, Express doesn't propagate the return value of a route handler function. 事实证明这有点像PITA,因为最终Express不会传播路由处理程序函数的返回值。

This is what I came up with (a monkey-patch): 这是我想出的(猴子补丁):

const Layer          = require('express/lib/router/layer');
const handle_request = Layer.prototype.handle_request;

Layer.prototype.handle_request = function(req, res, next) {
  if (! this.isWrapped && this.method) {
    let handle  = this.handle;
    this.handle = function(req, res, next) { // this is basically your wrapper
      let result = handle.apply(this, arguments);
      // do some independent processing
      return result;
    };
    this.isWrapped = true;
  }
  return handle_request.apply(this, arguments);
};

I would probably suggest using a similar approach as express-promise-router though, which implements a drop-in replacement for Express' Router . 我可能会建议使用类似的方法作为express-promise-router虽然,它实现了一个简易替换为Express的Router However, it's not implicit. 但是,它不是隐式的。

Why not just use next()? 为什么不只使用next()?

You can add stuff on req like 您可以在要求上添加内容,例如

app.get('/', (req, res, next) => {
    req.somestupidfieldthatidontevenknowwhyinamedthisway = 42;
    next();
});

app.get('/', (req, res, next) => {
    //req.somestupidfieldthatidontevenknowwhyinamedthisway is now accessible as 42
    var valueFromPreviousMiddleware = req.somestupidfieldthatidontevenknowwhyinamedthisway;
    .....
});

You could wrap middleware and router as below您可以如下包装中间件和路由器

function wrapper(func) {
    return function inner(req, res, next) {
        const start = Date.now();
        func(req, res, function () {
            let elapsedMS = Date.now() - start
            console.log('time elapsed for function ' + fn.prototype.constructor.name + ' is ' + elapsedMS)

            next.apply(this, arguments);
        });
    };
}


var originalAppUse = app.use;
app.use = function () {
    lastArg = arguments.length - 1;

    if (typeof arguments[lastArg] === 'function') {
        arguments[lastArg] = wrapper(arguments[lastArg])
    }

    originalAppUse.apply(this, arguments)
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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