Node.js 中间件包装

Node.js middleware wrap

我正在尝试编写自己的 node.js 服务器,到目前为止我有一个问题。

const asyncHandler = (fn) => async (req, res, next) => {
    try {
        if (!fn) next();
        await fn(req, res, next);
    } catch (e) {
        next(e);
    }
}

const errorHandler = (error, req, res, next) => {
    if (!error.code) {
        error = new InternalServerError(error.message ? error.message : 'Something broke');
    }
    const errorResponse = new MessageResponse(error.code, error.message);
    res.status(errorResponse.code).send(errorResponse.body);
}

这是两个中间件,第一个处理承诺拒绝,第二个是快速错误处理程序。 我正在使用第一个这样的

router.get('/', asyncHandler(async (req, res, next) => {
    let tasks = await TaskService.getAllTasks();
    tasks = tasks.map(task => {
        return task.entitize();
    })
}));

所以我需要将所有路由中间件函数包装到一个异步处理程序中来处理拒绝。但是如果我有 10000 个路由中间件函数呢?我可以写一些代码来默认将所有路由中间件函数包装到这个异步处理程序中吗?我的意思是这样写

router.get('/', async (req, res, next) => {
    throw new Error('aaa');
    let tasks = await TaskService.getAllTasks();
    tasks = tasks.map(task => {
        return task.entitize();
    })
});

而且这个中间件是被asyncHandler包装的?有人做过吗?我可以使用任何库来实现这一目标吗? 提前致谢。

您可以包装原始的 router.get 函数并在那里进行 async/error 处理,同时委托给原始函数。这样的事情应该有效:

const router = express.Router();    
const _route = router.route.bind(router);
const methodsToWrap = ['get', 'post', 'patch', 'delete'];

router.route = function(path) {
  const route = _route(path);
  for (const method of methodsToWrap) {
    if (route[method]) {
      route[method] = wrap(route[method]);
    }
  }
  return route;
};

function wrap(originRouterMethod) {
  return function() {
    const originMiddlewares = [...arguments];
    const wrappedMiddlewares = originMiddlewares.map(fn => {
      if (typeof fn !== `function`) {
        return fn;
      }

      return async function(req, res, next) {
        try {
          await fn.apply(null, arguments);
        } catch (err) {
          console.log('Caught error ' + err);
          next(err);
        }
      };
    });
    originRouterMethod.call(this, wrappedMiddlewares);
  };
}

有了它,您不需要将 asyncHandler 添加到设置中的所有路由,您只需将它们指定为:

...
router.get('/', async(req, res, next) => {
    let tasks = await TaskService.getAllTasks();
    tasks = tasks.map(task => {
            return task.entitize();
        });
});
...