资讯专栏INFORMATION COLUMN

教你从写一个迷你koa-router到阅读koa-router源码

yzzz / 1277人阅读

摘要:本打算教一步步实现,因为要解释的太多了,所以先简化成版本,从实现部分功能到阅读源码,希望能让你好理解一些。

本打算教一步步实现koa-router,因为要解释的太多了,所以先简化成mini版本,从实现部分功能到阅读源码,希望能让你好理解一些。
希望你之前有读过koa源码,没有的话,给你链接

最核心需求-路由匹配

router最重要的就是路由匹配,我们就从最核心的入手

router.get("/string",async (ctx, next) => {
  ctx.body = "koa2 string"
})

router.get("/json",async (ctx, next) => {
  ctx.body = "koa2 json"
})

我们希望

路径访问 /string 页面显示 "koa2 string"

路径访问 /json 页面显示 "koa2 json"

先分析
收集开发者输入的信息配置

1.我们需要一个数组,数组里每个都是一个对象,每个对象包含路径,方法,函数,传参等信息
这个数组我们起个名字叫stack

const stack = []

2.对于每一个对象,我们起名叫layer
我们把它定义成一个函数

function Layer() {
    
}

我们把页面比喻成一个箱子,箱子是对外的,箱子需要有入口,需要容纳。把每一个router比作放在箱子里的物件,物件是内部的

定义两个js页面,router.js做为入口,对于当前页面的访问的处理,layer.js包含开发者已经约定好的规则

router.js

module.exports = Router;

function Router(opts) {
  // 容纳layer层
  this.stack = [];
};

layer.js

module.exports = Layer;

function Layer() {

};

我们在Router要放上许多方法,我们可以在Router内部挂载方法,也可以在原型上挂载函数

但是要考虑多可能Router要被多次实例化,这样里面都要开辟一份新的空间,挂载在原型就是同一份空间。
最终决定挂载在原型上

方法有很多,我们先实现约定几个常用的吧

const methods = [
  "get",
  "post",
  "put",
  "head",
  "delete",
  "options",
];
methods.forEach(function(method) {
  Router.prototype[method] = function(path,middleware){
    // 对于path,middleware,我们需要把它交给layer,拿到layer返回的结果
    // 这里交给另一个函数来是实现,我们叫它register就是暂存的意思
    this.register(path, [method], middleware);
    // 因为get还可以继续get,我们返回this
    return this
  };
});
实现layer的沟通
Router.prototype.register = function (path, methods, middleware) {
  let stack = this.stack;
  let route = new Layer(path, methods, middleware);
  stack.push(route);
  
  return route
};

这里我们先去写layer

const pathToRegExp = require("path-to-regexp");

function Layer(path, methods, middleware) {
  // 把方法名称放到methods数组里
  this.methods = [];
  // stack盛放中间件函数
  this.stack = Array.isArray(middleware) ? middleware : [middleware];
  // 路径
  this.path = path;
  // 对于这个路径生成匹配规则,这里借助第三方
  this.regexp = pathToRegExp(path);
  // methods
  methods.forEach(function(method) {
    this.methods.push(method.toUpperCase());
    // 绑定layer的this,不然匿名函数的this指向window
  }, this);

};
// 给一个原型方法match匹配返回true
Layer.prototype.match = function (path) {
  return this.regexp.test(path);
};

回到router层

定义match方法,根据Developer传入的path, method返回 一个对象(包括是否匹配,匹配成功layer,和匹配成功的方法)

Router.prototype.match = function (path, method) {
  const layers = this.stack;
  let layer;
  const matched = {
    path: [],
    pathAndMethod: [],
    route: false
  };
   //循环寄存好的stack层的每一个layer
  for (var len = layers.length, i = 0; i < len; i++) {
    layer = layers[i];

    //layer是提前存好的路径, path是过来的path
    if (layer.match(path)) {
      // layer放入path,为什么不把path传入,一是path已经没用了,匹配了就够了,layer含有更多信息需要用
      matched.path.push(layer);
      //如果methods什么也没写,或者如果方法里含有你的过来的方法,那么把layer放入pathAndMethod
      if (layer.methods.length === 0 || ~layer.methods.indexOf(method)) {
        matched.pathAndMethod.push(layer);
        // 路径匹配,并且有方法
        if (layer.methods.length) matched.route = true;
      }
    }
  }

  return matched;
};

给Developer一个方法

app.use(index.routes())

这里不考虑传多个id,和多次匹配情况,拿到匹配的函数

Router.prototype.routes = function(){
  var router = this;

  const dispatch = function dispatch(ctx, next) {
    const path = ctx.path
    const method = ctx.method
    const matched = router.match(path, ctx.method);

    if (!matched.route) return next();
    const matchedLayers = matched.pathAndMethod
    // 先不考虑多matchedLayers多stack情况
    return matchedLayers[0].stack[0](ctx, next);
  }

  return dispatch
}

此时一个迷你koa-router已经实现了

读源码 需求实现 实现匹配

方法名匹配,路径匹配,还要满足动态参数的传递

并且还要给很懒的开发者一个router.all()
也就是说不用区分方法了

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/102805.html

相关文章

  • Koa-router 优先级问题

    摘要:问题描述在使用作为路由遇到了一个优先级问题如下代码在访问时路由会优先匹配到路由返回这个问题就很尴尬了项目空闲下来去翻看源码终于找到了原因问题原因的源码并不长和两个文件加起来共一千多行代码建议可以结合这篇文章阅读其中造成这个问题的原因 问题描述 在使用Koa-router作为路由遇到了一个优先级问题.如下代码 // routerPage.js file const router = re...

    Paul_King 评论0 收藏0
  • koa源码阅读[2]-koa-router

    摘要:第三篇,有关生态中比较重要的一个中间件第一篇源码阅读第二篇源码阅读与是什么首先,因为是一个管理中间件的平台,而注册一个中间件使用来执行。这里写入的多个中间件都是针对该生效的。 第三篇,有关koa生态中比较重要的一个中间件:koa-router 第一篇:koa源码阅读-0 第二篇:koa源码阅读-1-koa与koa-compose koa-router是什么 首先,因为koa是一个管...

    oneasp 评论0 收藏0
  • koa-router 源码浅析

    摘要:代码结构执行流程上面两张图主要将的整体代码结构和大概的执行流程画了出来,画的不够具体。那下面主要讲中的几处的关键代码解读一下。全局的路由参数处理的中间件组成的对象。 代码结构 showImg(https://segmentfault.com/img/remote/1460000007468236?w=1425&h=1772); 执行流程 showImg(https://segmentf...

    SillyMonkey 评论0 收藏0
  • 玩转Koa -- koa-router原理解析

    摘要:四路由注册构造函数首先看了解一下构造函数限制必须采用关键字服务器支持的请求方法,后续方法会用到保存前置处理函数存储在构造函数中初始化的和属性最为重要,前者用来保存前置处理函数,后者用来保存实例化的对象。 一、前言   Koa为了保持自身的简洁,并没有捆绑中间件。但是在实际的开发中,我们需要和形形色色的中间件打交道,本文将要分析的是经常用到的路由中间件 -- koa-router。   ...

    wthee 评论0 收藏0
  • iKcamp团队制作|基于Koa2搭建Node.js实战(含视频)☞ 路由koa-router

    路由koa-router——MVC 中重要的环节:Url 处理器 ?? iKcamp 制作团队 原创作者:大哼、阿干、三三、小虎、胖子、小哈、DDU、可木、晃晃 文案校对:李益、大力萌、Au、DDU、小溪里、小哈 风采主播:可木、阿干、Au、DDU、小哈 视频剪辑:小溪里 主站运营:给力xi、xty 教程主编:张利涛 视频地址:https://www.cctalk.com/v/151...

    netmou 评论0 收藏0

发表评论

0条评论

yzzz

|高级讲师

TA的文章

阅读更多
最新活动
阅读需要支付1元查看
<