内容简介:从上面可以知道,如果没有koa-router,其实每个路由使用的koa注册中间件的形式来进行处理的,这样不利于松耦合和模块化,所以将所有路由的处理逻辑抽离出来组合成一个大的中间件koa-router来处理,最后将大的中间件注册到koa上,如果关于koa中间件原理还不了解,可以参考另一篇文章既然koa-router也是大的中间件,里面拥有许多小的中间件,那么里面必然也需要用到洋葱模型,洋葱模型的特点:如果对于中间件和洋葱模型有疑问的,可以参考
- koa-session:让无状态的http拥有状态,基于cookie实现的后台保存信息的session
- koa-mysql:封装了需要用到的 SQL 语句
- koa-mysql-session:当不想让session存储到内存,而想让session存储到 mysql 数据库中时使用
- koa-router:后台会接受到各种请求的url,路由会根据不同的url来使用不同的处理逻辑。
- koa-view:请求html页面时,后台会用模板引擎渲染数据到模板上,然后返回给后台
- koa-static:请求img、js、css等文件时,不需要其他逻辑,只需要读取文件
- koa-better-body:post上传文件时,解析请求体
koa系列文章:
- koa框架会用也会写—(koa的实现)
- koa框架会用也会写—(koa-router)
- koa框架会用也会写—(koa-view、koa-static)
- koa框架会用也会写—(koa-bodyparser、koa-better-body)
koa-router的使用
var Koa = require('koa'); var Router = require('koa-router'); var app = new Koa(); var router = new Router(); router.get('/home',(ctx,next)=>{ ctx.body = 'home' next(); }); router.get('/user', (ctx, next) => { ctx.body = 'user'; next(); }); app.use(router.routes()).use(router.allowedMethods()); 复制代码
koa-router的奥秘
假如没有koa-router
var Koa = require('koa'); var Router = require('koa-router'); var app = new Koa(); var router = new Router(); //将路由的处理交给中间件 app.use((ctx, next) => { if (ctx.path === '/' && ctx.method === 'GET') { ctx.body = '首页' } else { next(); } }) app.use((ctx, next) => { if (ctx.path === '/user' && ctx.method === 'GET') { ctx.body = '用户' } else { next(); } }); 复制代码
从上面可以知道,如果没有koa-router,其实每个路由使用的koa注册中间件的形式来进行处理的,这样不利于松耦合和模块化,所以将所有路由的处理逻辑抽离出来组合成一个大的中间件koa-router来处理,最后将大的中间件注册到koa上,如果关于koa中间件原理还不了解,可以参考另一篇文章 koa框架会用也会写—(koa的实现)
koa-router的原理
既然koa-router也是大的中间件,里面拥有许多小的中间件,那么里面必然也需要用到洋葱模型,洋葱模型的特点:
- middles:存放中间件的容器,用来存放注册的中间件
- get(path,fn):用来注册中间件,往middles中存放,由于是路由中间件这里多了一个参数path
- compose():用来组合中间件,让路由中间件按顺序执行
- routes():用来将koa-router中间件注册到app的中间件上,主要作用是调用路由中间件匹配请求的路径ctx.path
如果对于中间件和洋葱模型有疑问的,可以参考 koa框架会用也会写—(koa的实现)
middles:存放中间件的容器,用来存放注册的中间件
class Router { constructor(){ this.middles=[]; } } module.exports = Router 复制代码
get(path,fn):用来注册中间件,往middles中存放,由于是路由中间件这里多了一个参数path
class Router { constructor(){ this.middles=[]; } get(path,fn){//set,post等同理 let layer = { path, fn, method } //处理类似/article/:id的路由 if(path.includes(':')){ let params = []; let reg = path.replace(/:([^\/]*)/g,function () { params.push(arguments[1]); //params = [id] return '([^\/]*)' //返会字符串/article/([^\/]*) }); //将返回的字符串变成正则,后面解析路由是会用到 layer.reg = new RegExp(reg);//返回/\/article\/([^\/]*)/ layer.params = params; } this.middles.push(layer); } } module.exports = Router 复制代码
compose():用来组合中间件,让路由中间件按顺序执行
class Router { constructor(){ this.middles=[]; } get(path,fn){//set,post等同理 let layer = { path, fn, method } //处理类似/article/:id的路由 if(path.includes(':')){ let params = []; let reg = path.replace(/:([^\/]*)/g,function () { params.push(arguments[1]); //params = [id] return '([^\/]*)' //返会字符串/article/([^\/]*) }); //将返回的字符串变成正则,后面解析路由是会用到 layer.reg = new RegExp(reg);//返回/\/article\/([^\/]*)/ layer.params = params; } this.middles.push(layer); } compose(lasts,next,ctx){//lasts为匹配的路由集合 dispatch(index){ if(index === lasts.length) return next(); let route = lasts[index]; //将路径参数都取出来exp:id的值 let params = route.params; let [, ...args] = pathname.match(route.reg); ctx.request.params = params.reduce((memo,key,index)=>(memo[key] = args[index], memo), {}); //执行路由逻辑,next赋值为下一个路由逻辑 route.fn(ctx,()=>{ dispatch(index+1); }) } dispatch(0) } } module.exports = Router 复制代码
routes():用来将koa-router中间件注册到app的中间件上,主要作用是调用路由中间件匹配请求的路径ctx.path
class Router { constructor(){ this.middles=[]; } get(path,fn){//set,post等同理 let layer = { path, fn, method } //处理类似/article/:id的路由 if(path.includes(':')){ let params = []; let reg = path.replace(/:([^\/]*)/g,function () { params.push(arguments[1]); //params = [id] return '([^\/]*)' //返会字符串/article/([^\/]*) }); //将返回的字符串变成正则,后面解析路由是会用到 layer.reg = new RegExp(reg);//返回/\/article\/([^\/]*)/ layer.params = params; } this.middles.push(layer); } compose(lasts,next,ctx){//lasts为匹配的路由集合 dispatch(index){ if(index === lasts.length) return next(); let route = lasts[index]; route.fn(ctx,()=>{ dispatch(index+1); }) } dispatch(0) } routes() { // ctx上下文next指的是koa中的next方法 return async (ctx, next) => { let pathname = ctx.path; //请求的路径 let lasts = this.middles.filter(item => { if (route.reg) { // 说明当前路由是一个路径参数 if (method === route.method && route.reg.test(pathname)) { return true //路径参数匹配到了,添加进路由组 } } if ((method === route.method || route.method === 'all') && (route.p === pathname || route.p === '*')) { return true //路径是'/'或者'all',添加进路由组 } return false; }); this.compose(lasts, next, ctx); } } } module.exports = Router 复制代码
以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网
猜你喜欢:- 基于Google MVVM框架的baseMVVM框架
- Spring 框架是怎么出生的(二):重构提炼出框架
- Spring 框架是怎么出生的(二):重构提炼出框架
- Genesis框架从入门到精通(7): 框架的过滤器
- 如何打造自己的POC框架-Pocsuite3-框架篇
- 如何打造自己的PoC框架-Pocsuite3-框架篇
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。