使用中间件和下一个回调

Express 将 next 回调传递给每个路由处理程序和中间件函数,这些函数可用于破坏跨多个处理程序的单个路由的逻辑。在没有参数的情况下调用 next() 会告诉 express 继续使用下一个匹配的中间件或路由处理程序。使用错误调用 next(err) 将触发任何错误处理程序中间件。调用 next('route') 将绕过当前路由上的任何后续中间件并跳转到下一个匹配路由。这允许将域逻辑分离为可重用的组件,这些组件是独立的,更易于测试,更易于维护和更改。

多条匹配路线

/api/foo/api/bar 的请求将运行初始处理程序以查找成员,然后将控制权传递给每个路由的实际处理程序。

app.get('/api', function(req, res, next) {
  // Both /api/foo and /api/bar will run this
  lookupMember(function(err, member) {
    if (err) return next(err);
    req.member = member;
    next();
  });
});

app.get('/api/foo', function(req, res, next) {
  // Only /api/foo will run this
  doSomethingWithMember(req.member);
});

app.get('/api/bar', function(req, res, next) {
  // Only /api/bar will run this
  doSomethingDifferentWithMember(req.member);
});

错误处理程序

错误处理程序是具有签名 function(err, req, res, next) 的中间件。它们可以按路由设置(例如 app.get('/foo', function(err, req, res, next)),但通常,呈现错误页面的单个错误处理程序就足够了。

app.get('/foo', function(req, res, next) {
  doSomethingAsync(function(err, data) {
    if (err) return next(err);
    renderPage(data);
  });
});

// In the case that doSomethingAsync return an error, this special
// error handler middleware will be called with the error as the 
// first parameter.
app.use(function(err, req, res, next) {
  renderErrorPage(err);
});

中间件

上述每个函数实际上都是一个中间件函数,只要请求与定义的路由匹配就会运行,但是可以在单个路由上定义任意数量的中间件函数。这允许在单独的文件和通用逻辑中定义中间件,以便在多个路由上重用。

app.get('/bananas', function(req, res, next) {
  getMember(function(err, member) {
    if (err) return next(err);
    // If there's no member, don't try to look
    // up data. Just go render the page now.
    if (!member) return next('route');
    // Otherwise, call the next middleware and fetch
    // the member's data.
    req.member = member;
    next();
  });
}, function(req, res, next) {
  getMemberData(req.member, function(err, data) {
    if (err) return next(err);
    // If this member has no data, don't bother
    // parsing it. Just go render the page now.
    if (!data) return next('route');
    // Otherwise, call the next middleware and parse
    // the member's data. THEN render the page.
    req.member.data = data;
    next();
  });
}, function(req, res, next) {
  req.member.parsedData = parseMemberData(req.member.data);
  next();
});

app.get('/bananas', function(req, res, next) {
  renderBananas(req.member);
});

在此示例中,每个中间件函数都可以位于其自己的文件中,也可以位于文件中其他位置的变量中,以便可以在其他路径中重复使用。