ExpressJS 4中间件问题
我试图用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);
除了在/test/1
和/test/2
上调用/test/1
时打印OK
。
app.use("/test/", router2.use(middleware), router1);
但是输出似乎是倒置的,相当于:
app.use("/test/", router2, middleware, router1);
我真正想要的只是第一台使用中间件的路由器。 换句话说,将中间件用于第一个控制器。
我可以很容易地交换router1
和router2
的顺序,但是我的其他要求是因为我的router2
实际上使用了一个能够捕获所有请求( /:id
)的路由,我需要最后一个。
我在这里错过了什么,我该怎么做我想要的?
编辑澄清:
我最终想要的是这样的东西:
/ |-test/ |-route // use middleware |-something // use middleware |-another // use middleware ... |-:id // without middleware
这就是为什么我有一个路由器有许多路由在我想要的中间件router1
。 而router2
与一个没有中间件的catch-all。
定义路由时可以设置一个中间件:
router1.get("/1", middleware, handler); router2.get("/2", handler);
第一个将使用中间件,第二个不使用。
顺便说一句,我会build议如下:不要为每个路由创build单独的路由器,只有一个就足够了。
const router = express.Router(); router.get("/1", handler); router.get("/2", handler); app.use("/test/", router);
由于router1
和router2
绑定到一个公共路由,它们将按顺序执行,以及它们的中间件,直到其中一个路由器与请求的path/路由匹配。
在你的情况下,因为你不能交换路由器的顺序,你可以创build一个包裹路由器的中间件,检查路由器中是否存在请求的path/路由,如果是的话,返回它,否则就跳过它。
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);