Express.js - обернуть каждое промежуточное ПО / маршрут в «декоратор»

1

У меня есть экземпляр Express.js и несколько маршрутов, которые я хочу обернуть некоторой функцией. Пример:

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

Хотя это прекрасно работает, мне не нравится идея явно называть wrapper на каждом маршруте или промежуточном программном обеспечении, требующем такой обработки.

Есть ли способ обернуть каждый необходимый маршрут/промежуточное ПО в определенную оболочку (учитывая, что функция- wrapper может проверять, что этот маршрут/промежуточное программное обеспечение необходимо обернуть) неявно (через расширение Express.js, исправление обезьяны или какое-то специальное промежуточное ПО)?

ОБНОВИТЬ:

Более солидный пример. Предположим, что я хочу сделать async функции маршрутизатора. Но я не хочу ломать ошибки в каждой функции маршрута. Поэтому я завершаю их:

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

Эта явная wrapper вокруг всех маршрутов на самом деле является тем, от чего я хочу избавиться.

Теги:
express
middleware

2 ответа

2
Лучший ответ

Это оказалось немного PITA, потому что, в конечном счете, Express не распространяет возвращаемое значение функции обработчика маршрута.

Это то, что я придумал (обезьяна-патч):

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

Вероятно, я бы предложил использовать аналогичный подход, например, express-promise-router, который реализует замену для Express ' Router. Однако это не подразумевается.

  • 0
    Спасибо за ответ. Но это относится не только к возвращаемым значениям функции маршрутизатора. Позвольте мне обновить мою функцию с более явным примером.
  • 0
    @KidBinary Довольно просто использовать предоставленный пример для реализации того, что вы хотите ( if (result.catch) { ... } ). Очевидно, вы также можете переписать его в служебную функцию, чтобы скрыть кровавые подробности.
Показать ещё 3 комментария
0

Почему бы просто не использовать next()?

Вы можете добавить материал в req как

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;
    .....
});
  • 0
    Потому что это на самом деле не в этом дело. Позвольте мне обновить мой вопрос.

Ещё вопросы

Сообщество Overcoder
Наверх
Меню