问题描述
在使用 Koa-router 作为路由遇到了一个优先级问题.如下代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| const router = require("koa-router"); router.get("/test", (ctx) => { ctx.body = "test"; }); router.get("/router/test", (ctx) => { ctx.body = "router test"; }); module.exports = router;
const router = require("koa-router"); const routerPage = require("./routerPage"); router.use(routerPage.routes(), routerPage.allowedMethods()); module.exports = router;
|
在访问"/router/test"
时路由会优先匹配到"/test"
路由,返回ctx.body = "test"
,这个问题就很尴尬了,项目空闲下来去翻看源码终于找到了原因
问题原因
Koa-router 的源码并不长,layer.js 和 router.js 两个文件加起来共一千多行代码.建议可以结合这篇文章阅读.
其中造成这个问题的原因就是 router.js 中router.use
这个方法,方法源码如下
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40
| Router.prototype.use = function () { var router = this; var middleware = Array.prototype.slice.call(arguments); var path = "(.*)";
if (Array.isArray(middleware[0]) && typeof middleware[0][0] === "string") { middleware[0].forEach(function (p) { router.use.apply(router, [p].concat(middleware.slice(1))); });
return this; } var hasPath = typeof middleware[0] === "string"; if (hasPath) { path = middleware.shift(); } middleware.forEach(function (m) { if (m.router) { m.router.stack.forEach(function (nestedLayer) { if (path) nestedLayer.setPrefix(path); if (router.opts.prefix) nestedLayer.setPrefix(router.opts.prefix); router.stack.push(nestedLayer); });
if (router.params) { Object.keys(router.params).forEach(function (key) { m.router.param(key, router.params[key]); }); } } else { router.register(path, [], m, { end: false, ignoreCaptures: !hasPath }); } });
return this; };
|
问题就出在router.use(routerPage.routes(), routerPage.allowedMethods())
时没有设置前缀,
路由就自动添加了默认的前缀"(.*)"
,这里的 path 发生了改变,在路由后续的操作中,将 path 使用pathToRegExp
转换成正则表达式时"/test"
这个 path 本应该是/^\/test...../
就会变成/(.*)/\/test...
(大概是这个意思)
那么原本以/test
开头的路由就会匹配包含/test
的路由
所以 request path 为/router/test
时会被/test
路由先匹配中,路由也就不会往下匹配
解决方式
- 将条件更精确的路由放到前面
- 在
/test
那个路由中加一个中间件,当匹配到/router/test
时 await next()
继续向下执行
- 更改源码
Router.propertype.use
中 path = "(.*)"
为 path = false
- 在使用
router.use
时代码做一定更改,代码如下
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| const router = require("koa-router"); router.get("test", (ctx) => { ctx.body = "test"; }); router.get("router/test", (ctx) => { ctx.body = "router test"; }); module.exports = router;
const router = require("koa-router"); const routerPage = require("./routerPage"); router.use("/", routerPage.routes(), routerPage.allowedMethods()); module.exports = router;
|
如果您喜欢此博客或发现它对您有用,则欢迎对此发表评论。 也欢迎您共享此博客,以便更多人可以参与。 如果博客中使用的图像侵犯了您的版权,请与作者联系以将其删除。 谢谢 !