首页 > 其他分享 >#yyds干货盘点#Koa-router 优先级问题

#yyds干货盘点#Koa-router 优先级问题

时间:2023-09-22 14:32:41浏览次数:39  
标签:yyds Koa ctx routerPage router test path 路由

问题描述

在使用Koa-router作为路由遇到了一个优先级问题.如下代码

// routerPage.js file
const router = require("koa-router")
router.get("/test", ctx => { ctx.body = "test" })
router.get("/router/test", ctx => { ctx.body = "router test" })
module.exports = router

// routerIndex.js file
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这个方法,方法源码如下

// 主要作用: 给path添加中间件
Router.prototype.use = function () {
  var router = this;
  var middleware = Array.prototype.slice.call(arguments);
  var path = '(.*)';

  // 如果path为array则递归调用use方法
  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;
  }
  //如果传入了path,则只对此path操作
  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路由先匹配中,路由也就不会往下匹配

解决方式

  1. 将条件更精确的路由放到前面
  2. /test那个路由中加一个中间件,当匹配到/router/test时 await next()继续向下执行
  3. 更改源码Router.propertype.use 中 path = "(.*)" 为 path = false
  4. 在使用router.use时代码做一定更改,代码如下
// routerPage.js file
const router = require("koa-router")
router.get("test", ctx => { ctx.body = "test" })
router.get("router/test", ctx => { ctx.body = "router test" })
module.exports = router

// routerIndex.js file
const router = require("koa-router")
const routerPage = require("./routerPage")
router.use("/", routerPage.routes(), routerPage.allowedMethods())
module.exports = router

标签:yyds,Koa,ctx,routerPage,router,test,path,路由
From: https://blog.51cto.com/u_11365839/7565374

相关文章

  • KOA 框架最常用的 15 个中间件!
    koa-router:提供全面的路由功能,比如类似Express的app.get/post/put的写法,URL命名参数、路由命名、嵌套路由、支持加载多个中间件koa-bodyparser:post提交数据中间件,解析请求体时需要加载的中间件,支持x-www-form-urlencoded,application/json等格式的请求体,不支持form-data的请求......
  • # yyds干货盘点 # 系统提取的部分数据存在异常,Python填充有其他更简单的方法么?
    大家好,我是皮皮。一、前言前几天在Python最强王者群【wen】问了一个Python自动化办公的问题,一起来看看吧。请教问题:友信平台因为系统提取的部分数据存在异常,导出的数据经常缺失客户名,但是客户账号是准确的,如果实现客户名自动填充?解决思路:1单独生成客户账号和客户名的表格,两个表格进......
  • #yyds干货盘点# LeetCode程序员面试金典:二叉搜索树的最近公共祖先
    题目:给定一个二叉搜索树,找到该树中两个指定节点的最近公共祖先。百度百科中最近公共祖先的定义为:“对于有根树T的两个结点p、q,最近公共祖先表示为一个结点x,满足x是p、q的祖先且x的深度尽可能大(一个节点也可以是它自己的祖先)。”例如,给定如下二叉搜索树: root= [6,2......
  • #yyds干货盘点# LeetCode程序员面试金典:建立四叉树
    1.简述:给你一个 n*n 矩阵 grid ,矩阵由若干 0 和 1 组成。请你用四叉树表示该矩阵 grid 。你需要返回能表示矩阵 grid 的四叉树的根结点。四叉树数据结构中,每个内部节点只有四个子节点。此外,每个节点都有两个属性:val:储存叶子结点所代表的区域的值。1对应 True,0对......
  • vue_vueRouter同组件跳转失败
    目录场景再现资料查询解决场景再现现有一个Article页面,通过/article/:id来匹配不同的文章页面,当我需要实现跳转到上一篇或下一篇时,即从/article/:id跳转另一个/article/:id时,发现浏览器中只有地址变化了,但是页面的很多组件,包括文章内容都没有刷新,资料查询这......
  • 【HarmonyOS】元服务卡片router实现跳转到指定页面
    ​【关键字】元服务卡片、router跳转不同页面 【写在前面】本篇文章主要介绍开发元服务卡片时,如何实现从卡片中点击事件跳转到指定的应用内页面功能。此处以JSUI开发服务卡片为例,JS卡片支持组件设置action,包括router事件和message事件,其中router事件用于应用跳转,message事件......
  • #yyds干货盘点#Redux 的基本使用
    1.核心概念1.什么是Redux?Redux是一个管理状态(数据)的容器,提供了可预测的状态管理2.什么是可预测的状态管理?数据在什么时候,因为什么,发生了什么改变,都是可以控制和追踪的,我们就称之为预测的状态管理3.为什么要使用Redux?React是通过数据驱动界面更新的,React负责更新界面,而我们负责......
  • #yyds干货盘点#TypeScript条件类型
    索引类型keyof会提取interface中的keyclassKeyCls{name:stringage:number}typeKeyClsExample1=keyofKeyCls//name|agefunctiongetParams(params:keyofKeyCls){}getParams('name')//正常getParams('age')//正常getParams('sex......
  • # yyds干货盘点 #盘点一个Python打包的报错问题
    大家好,我是皮皮。一、前言前几天在Python钻石群【年鱼鱼......
  • vue-router 编程式导航
    导航到不同的位置注意:在Vue实例中,你可以通过 $router 访问路由实例。因此你可以调用 this.$router.push。想要导航到不同的URL,可以使用 router.push 方法。这个方法会向history栈添加一个新的记录,所以,当用户点击浏览器后退按钮时,会回到之前的URL。该方法的参数可以......