如何为/api下不同子路由配置不同Express中间件(无需逐个设置)?
问题
希望在/api路径下的不同路由使用不同的中间件处理器,让不同API路由支持不同认证方式。尝试将不同API路由嵌套在两个带有不同中间件的Router中,代码如下:
const express = require("express"); const app = express(); const port = 4000; const one = express.Router(); one.use((req, res, next) => { console.log("one"); next(); }); one.get("/api/one", (req, res) => { console.log("/api/one"); res.send("one"); }); // --- const two = express.Router(); two.use((req, res, next) => { console.log("two"); next(); }); two.get("/api/two", (req, res) => { console.log("/api/two"); res.send("two"); }); // --- app.get("/", (req, res) => { res.send("Hello World!"); }); app.use(one); app.use(two); app.listen(port, () => { console.log(`Example app listening on port ${port}`); });
期望访问/api/one时仅打印"one",访问/api/two时仅打印"two",但实际访问/api/two时两个中间件都执行了:
Example app listening on port 4000 one /api/one one two /api/two
请问是否有办法实现需求且无需为每个API路由单独列出不同中间件?
解决方案
问题根源在于你给子Router定义了完整的/api/xxx路由,同时直接将Router挂载到根路径。Express中,当你用app.use(one)挂载Router时,它会匹配所有请求,接着检查Router内部的路由是否匹配,不匹配就会继续向下传递,导致多个Router的中间件被触发。
方法一:给子Router指定挂载前缀
给每个子Router设置挂载前缀,同时子Router内部使用相对路径:
const express = require("express"); const app = express(); const port = 4000; const one = express.Router(); one.use((req, res, next) => { console.log("one"); next(); }); // 内部路由写相对路径,对应挂载后的/api/one one.get("/", (req, res) => { console.log("/api/one"); res.send("one"); }); const two = express.Router(); two.use((req, res, next) => { console.log("two"); next(); }); two.get("/", (req, res) => { console.log("/api/two"); res.send("two"); }); app.get("/", (req, res) => { res.send("Hello World!"); }); // 只有请求路径匹配前缀时,才会触发对应Router的中间件 app.use("/api/one", one); app.use("/api/two", two); app.listen(port, () => { console.log(`Example app listening on port ${port}`); });
这样修改后,访问/api/one仅触发one的中间件,访问/api/two仅触发two的中间件,无需为单个路由单独配置中间件。
方法二:使用层级Router(适合多API路由场景)
先创建一个根/api Router,再将不同子Router挂载到它下面,结构更清晰:
const express = require("express"); const app = express(); const port = 4000; // 根API Router const apiRouter = express.Router(); const one = express.Router(); one.use((req, res, next) => { console.log("one"); next(); }); one.get("/", (req, res) => { console.log("/api/one"); res.send("one"); }); const two = express.Router(); two.use((req, res, next) => { console.log("two"); next(); }); two.get("/", (req, res) => { console.log("/api/two"); res.send("two"); }); // 挂载子Router到根API Router apiRouter.use("/one", one); apiRouter.use("/two", two); // 将根API Router挂载到/app路径 app.use("/api", apiRouter); app.get("/", (req, res) => { res.send("Hello World!"); }); app.listen(port, () => { console.log(`Example app listening on port ${port}`); });
这种方式的层级结构更易于维护,尤其适合API路由较多的项目。
内容的提问来源于stack exchange,提问作者Stuart K
相关产品推荐
相关产品推荐

