koa-router源码地址是 koa-router

当前解读版本为7.2.1

关系图

代码结构图



执行流程图



关系对应图

Router方法和属性浅析

methods.forEach

注册注册路由的方法,结果就是Router的原型上面多了get,post,delete,del等注册路由的方法

代码使用的时候 r1.get就是这么来的

r1.get('/test1/:id', function (ctx, next) {
console.log('test1 :1')
next()
}, function (ctx, next) {
console.log('test1:2')
})

Router.prototype.del

等同于 Router.prototype.delete

Router.prototype.use

注册中间件,支持形式多种多样

看着这么多,其实就两种中间件,

  • 普通中间件
  • router.routes()返回的中间件

重点就是router.routes()返回的这种件,需要的前缀,参数验中间件做一些处理

  router.use(function (ctx, next) {
ctx.foo = 'baz';
return next();
});
router.use('/foo/bar', function (ctx, next) {
ctx.foo = 'foo';
return next();
});
router.use('/foo', subrouter.routes());
router.use(['/foo', '/bar'], function (ctx, next) {
ctx.foo = 'foo';
ctx.bar = 'bar';
return next();
});
parentRouter.use('/parent-route', function (ctx, next) {
ctx.n = ctx.n ? (ctx.n + 1) : 1;
return next();
}, nestedRouter.routes());

Router.prototype.prefix

给router实例添加前缀,前缀可以是包含参数的

  router.prefix('/things/:thing_id')

Router.prototype.routes = Router.prototype.middleware

返回中间件,

中间执行的时候,会根据path获取满足匹配条件的路由(Layer),然后根据每个Layer生成一个解析参数值的中间,这就是为什么我们在ctx.params能得到参数值

最核心的代码如下

    layerChain = matchedLayers.reduce(function(memo, layer) {
memo.push(function(ctx, next) {
ctx.captures = layer.captures(path, ctx.captures);
ctx.params = layer.params(path, ctx.captures, ctx.params);
return next();
});
return memo.concat(layer.stack);
}, []);
return compose(layerChain)(ctx, next);

matchedLayers是匹配的Layer或者说一条路由信息,同一个路径同样的方法也是会生成两条记录的,如下同样的注册,会生成两个不同路由(Layer),哪怕信息一模一样

r1.get('/test1', function (ctx, next) {
console.log('test1 :1')
next()
}) r1.get('/test1', function (ctx, next) {
console.log('test1 :2')
next()
})

matchedLayers.reduce没执行一次,是生成两个中间件,

一个是参数解析的中间件,这就是为什么你可以通过ctx.params取值到路由参数了

function(ctx, next) {
ctx.captures = layer.captures(path, ctx.captures);
ctx.params = layer.params(path, ctx.captures, ctx.params);
return next();
}

另外一个才是实际路由匹配的执行方法,上面的demo就是

function (ctx, next) {
console.log('test1 :1')
next()
}

Router.prototype.allowedMethods

此方法执行很靠后,在他后面注册的中间件执行完毕后才执行

生成一个中间件,作用是定义路由没匹配到,方法未允许,方法未实现等的返回信息

  app.use(router.routes());
app.use(router.allowedMethods({
throw: true,
notImplemented: () => new Boom.notImplemented(),
methodNotAllowed: () => new Boom.methodNotAllowed()
}));

Router.prototype.all

注册一个路由,允许所有的get,post等方法访问

Router.prototype.redirect

跳转,原理就是注册了一个路由,用ctx.redirect来实现跳转

router.redirect('/login', 'sign-in');

等同于

router.all('/login', function (ctx) {
ctx.redirect('/sign-in');
ctx.status = 301;
});

Router.prototype.register

核心方法之一,注册中间件

Router.prototype.all,methods.forEach等底层都是调用这个家伙实现的

Router.prototype.use也依据情况会调用

Router.prototype.route

查找具名的route(Layer)

Router.prototype.url

生成url,可以传参

router.get('user', '/users/:id', function (ctx, next) {
// ...
});
router.url('user', 3);
// => "/users/3"
router.url('user', { id: 3 });
// => "/users/3"
router.use(function (ctx, next) {
// redirect to named route
ctx.redirect(ctx.router.url('sign-in'));
})

Router.prototype.match

获得匹配的路由(Layer),以path和method来过滤的

router.routes返回的中间件底层就是通过他来确认请求应该进入哪些路由的

Router.prototype.param

添加参数验证中间件,这个需要结合Layer.prototype.param 一起来理解

Router.prototype.param = function (param, middleware) {
this.params[param] = middleware;
this.stack.forEach(function (route) {
route.param(param, middleware);
});
return this;
}; Layer.prototype.param = function (param, fn) {
var stack = this.stack;
var params = this.paramNames;
// 构建参数验证中间件
var middleware = function (ctx, next) {
return fn.call(this, ctx.params[param], ctx, next);
};
middleware.param = param; var names = params.map(function (p) {
return p.name;
}); var x = names.indexOf(param);
if (x > -1) {
// iterate through the stack, to figure out where to place the handler fn
stack.some(function (fn, i) {
// param handlers are always first, so when we find an fn w/o a param property, stop here
// if the param handler at this part of the stack comes after the one we are adding, stop here
// fn.param 作为判断是不是参数验证中间件的标志
// 如果不是参数验证中间件,或者参数验证中间件需要验证的参数在我之后,插入参数验证中间件
// 比如说path是这样的 /user/:id/posts/:postid, 那么id参数验证中间件应该在postid参数之前
// 简单说,确保参数按照顺序被验证
if (!fn.param || names.indexOf(fn.param) > x) {
// inject this param handler right before the current item
stack.splice(i, 0, middleware);
return true; // then break the loop
}
});
} return this;
};

Layer方法和属性浅析

Layer.prototype.match

path是否匹配路由

Layer.prototype.params

获得路由参数键值对

Layer.prototype.captures

获得路由参数的值

Layer.prototype.url

用参数构建URL,params参数可视是对象也可是数组

Layer.prototype.param

添加参数验证中间件

Layer.prototype.setPrefix

设置前缀

safeDecodeURIComponent

decodeURIComponent错误时返回原值

更多细节请直接看带备注的源码吧,写东西真累啊!

Router

Layer

koa-router 源码解析 - segmentfault

解析Koa-Router,迈入Web次时代第一步(上)

Koa-Router 源码解析下 -CNode

koa-router源码解读

Koa-router 优先级问题

Path-to-RegExp 使用

koa-router源码分析的更多相关文章

  1. 手写@koa/router源码

    上一篇文章我们讲了Koa的基本架构,可以看到Koa的基本架构只有中间件内核,并没有其他功能,路由功能也没有.要实现路由功能我们必须引入第三方中间件,本文要讲的路由中间件是@koa/router,这个中 ...

  2. Koa源码分析(三) -- middleware机制的实现

    Abstract 本系列是关于Koa框架的文章,目前关注版本是Koa v1.主要分为以下几个方面: Koa源码分析(一) -- generator Koa源码分析(二) -- co的实现 Koa源码分 ...

  3. Koa源码分析(二) -- co的实现

    Abstract 本系列是关于Koa框架的文章,目前关注版本是Koa v1.主要分为以下几个方面: Koa源码分析(一) -- generator Koa源码分析(二) -- co的实现 Koa源码分 ...

  4. Koa源码分析(一) -- generator

    Abstract 本系列是关于Koa框架的文章,目前关注版本是Koa v1.主要分为以下几个方面: 1. Koa源码分析(一) -- generator 2. Koa源码分析(二) -- co的实现 ...

  5. Dubbo 源码分析 - 集群容错之 Router

    1. 简介 上一篇文章分析了集群容错的第一部分 -- 服务目录 Directory.服务目录在刷新 Invoker 列表的过程中,会通过 Router 进行服务路由.上一篇文章关于服务路由相关逻辑没有 ...

  6. koa2中间件koa和koa-compose源码分析原理(一)

    koa是基于nodejs平台的下一代web开发框架,它是使用generator和promise,koa的中间件是一系列generator函数的对象.当对象被请求过来的时候,会依次经过各个中间件进行处理 ...

  7. koa源码分析

    最近项目要使用koa,所以提前学习一下,顺便看了koa框架的源码. 注:源码是koa2.x koa的源码很简洁,关键代码只有4个文件,当然还包括一些依赖npm包 const Koa = require ...

  8. flask源码分析

    本flask源码分析不间断更新 而且我分析的源码全是我个人觉得是很beautiful的 1 flask-login 1.1 flask.ext.login.login_required(func),下 ...

  9. Backbone.js源码分析(珍藏版)

    源码分析珍藏,方便下次阅读! // Backbone.js 0.9.2 // (c) 2010-2012 Jeremy Ashkenas, DocumentCloud Inc. // Backbone ...

  10. docker 源码分析 一(基于1.8.2版本),docker daemon启动过程;

    最近在研究golang,也学习一下比较火的开源项目docker的源代码,国内比较出名的docker源码分析是孙宏亮大牛写的一系列文章,但是基于的docker版本有点老:索性自己就git 了一下最新的代 ...

随机推荐

  1. JavaScript创建对象的方法

    显示在浏览器中的控制台中. <script type="text/javascript"> //这个工厂方法返回一个新的"范围对象" functio ...

  2. .NetCore~C#6的一些新特性

    回到目录 在进行.netCore平台后,由于它的版本在.net4.6,C#6之后,所以它的语法也有一些新的特性,主要表现在以下几个方面 只读属性初始化 static string Hello => ...

  3. CJOJ 1494 【网络流24题】 搭配飞行员(二分图最大匹配)

    CJOJ 1494 [网络流24题] 搭配飞行员(二分图最大匹配) Description 飞行大队有若干个来自各地的驾驶员,专门驾驶一种型号的飞机,这种飞机每架有两个驾驶员,需一个正驾驶员和一个副驾 ...

  4. Go语言学习笔记(四)结构体struct & 接口Interface & 反射

    加 Golang学习 QQ群共同学习进步成家立业工作 ^-^ 群号:96933959 结构体struct struct 用来自定义复杂数据结构,可以包含多个字段(属性),可以嵌套: go中的struc ...

  5. (转)Linux下增加交换分区的大小

    场景:最近在Linux环境安装ELK相关软件时候发现机器特别的卡,所以就查看了Linux机器的内存使用情况,发现是内存和交换分区空间太小了. 对于虚拟机中的内存问题,可以直接通过更改虚拟机的硬件进行解 ...

  6. (转)生产者/消费者问题的多种Java实现方式 (待整理)

    实质上,很多后台服务程序并发控制的基本原理都可以归纳为生产者/消费者模式,而这是恰恰是在本科操作系统课堂上老师反复讲解,而我们却视而不见不以为然的.在博文<一种面向作业流(工作流)的轻量级可复用 ...

  7. jsp变量的使用规则

    jsp是一种弱类型的交而不能语音,虽然看似没有像强类型语言那么多的代码规范,但是在实际使用的过程当中依然有不少的问题.下面就简单的梳理一下. 1.首先,jsp是一种弱类型的脚本语言,变量在使用之前无需 ...

  8. 利用GPU实现大规模动画角色的渲染

    0x00 前言 我想很多开发游戏的小伙伴都希望自己的场景内能渲染越多物体越好,甚至是能同时渲染成千上万个有自己动作的游戏角色就更好了. 但不幸的是,渲染和管理大量的游戏对象是以牺牲CPU和GPU性能为 ...

  9. Tomcat和Java Virtual Machine的性能调优总结

    就算生不逢时,也该理解理解了.已经在Java界快混迹3年了,对于一些性能调优的话题我是一直插不上嘴,只是针对昨晚看到的一篇性能调优的文章,我忍不住了. Tomcat性能调优: 找到Tomcat根目录下 ...

  10. 仿PC版微信的练手项目(可实时通讯)

    仿PC版微信的DEMO 本项目是由一个仿PC版微信的vue前端项目,和一个使用leancloud进行数据存储的.提供WebSocket的node后端项目构成. 本项目使用的技术栈:vue + vue- ...