ExpressJS 4中间件问题

时间:2017-05-24 08:13:07

标签: javascript node.js express router middleware

我试图在ExpressJS 4中将中间件包裹起来。

如果我理解正确的是中间件是按照声明的顺序应用的,那么你可以"绑定"他们处于不同的层面。

我试图在路由器级绑定中间件。

function middleware(req, res, next) {
  console.log("middleware");
  res.write("middleware");
  next();
}
function handler(req, res) {
 console.log("OK");
 res.status(200).send('OK');
}

const router1 = express.Router();
const router2 = express.Router();

router1.get("/1", handler);
router2.get("/2", handler);

我会在OK上调用/test/1middleware时打印/test/2以外的其他内容。

app.use("/test/", router2.use(middleware), router1);

但输出似乎是倒置的,相当于:

app.use("/test/", router2, middleware, router1);

我真正想要的是只有第一个使用中间件的路由器。 换句话说,将中间件用于第一个控制器。

我可以轻松交换router1router2的顺序,但我的其他要求是因为我的router2实际上使用了捕获所有请求的路由(/:id)我需要持续下去。

我在这里失踪了什么,我怎么能做我想做的事?

编辑澄清:

我最想要的是这个:

/
 |-test/
    |-route         // use middleware
    |-something     // use middleware  
    |-another       // use middleware
    ...
    |-:id           // without middleware

这就是为什么我的路由器有很多路由在router1下我需要中间件的地方。 而且router2有一个没有中间件的全能。

2 个答案:

答案 0 :(得分:1)

您可以在定义路线时设置中间件:

router1.get("/1", middleware, handler);
router2.get("/2", handler);

第一个将使用中间件,第二个不使用。

BTW我建议如下:不要为每条路线创建单独的路由器,只有一条就够了。

const router = express.Router();

router.get("/1", handler);
router.get("/2", handler);

app.use("/test/", router);

答案 1 :(得分:1)

router1router2绑定到一个公共路由时,它们将按顺序执行,连同它们的中间件,直到其中一个路由器路由与请求的路径/路由匹配。

在您的情况下,由于您无法交换路由器的顺序,您可以创建一个包装路由器的中间件,检查路由器中是否存在请求的路径/路由,如果是,则返回它,否则只是跳过它

var unlessMatch = function(router) {
    let routerPaths = [];

    // Retrieve, create a regex and store every route of the Router
    router.stack.forEach(layer => {
        if (layer.route) {
            routerPaths.push(layer.route.path.replace(/\/?(:[^\/]+)(\/?)/g, "/[^\/]+"));
        }
    });

    return function(req, res, next) {
        // Check if requested route exists in the router
        routerPaths.every(path => {
            return new RegExp('^' + path + '(\/)?$').test(req.path) ? router(req, res, next) : true;
        });

        return next();
    };
};

function middleware(req, res, next) {
    console.log("middleware");
    next();
}

function handler(req, res) {
    console.log("OK");
    res.status(200).send('OK');
}

const router1 = express.Router();
const router2 = express.Router();

// Bind middleware to router2
router2.use(middleware);

router1.get("/1", handler);
router2.get("/2", handler);

// Wrap router2 into unlessMatch middleware/function so that router2's middlewares
// are not executed if no route matches with the requested one
app.use("/test/", unlessMatch(router2), router1);