koa框架会用也会写—(koa-router)

4,775 阅读4分钟

Koa中常用的中间件:

  • 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-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())
app.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的基础架构)

layer: 存放注册的路由信息

class Layer {
    constructor(path,callback) {
	this.path = path	//路由路径
        this.cb = callback	//对应的处理函数
    }
}

middles:存放中间件的容器,用来存放注册的中间件

class Router {
    constructor() {
        this.middles = [];
    }
}
module.exports = Router

get:用来注册中间件,往middles中存放,由于是路由中间件这里多了一个参数path

class Router {
    constructor() {
        this.middles = [];
    }
    //set,post等同理
    get(path,callback) {
    	const layer = new Layer(path,callback)
    	this.middles.push(layer)
    }
}
module.exports = Router

routes:用来将koa-router中间件注册到app的中间件上,主要作用是调用路由中间件匹配请求的路径ctx.path

class Router {
    constructor(){
        this.middles=[];
    }
    //set,post等同理
    get(path,fn){
        const layer = new Layer(path,callback)
    	this.middles.push(layer)
    }
    compose(){}
    routes() {
    // 返回一个组合的中间件router.routes供app.use注册
    // next是koa-router之后app.use注册的中间件
    return async (ctx, next) => {
      // 请求的路径
      let path = ctx.path;
      // 和路径匹配的路由的处理函数
      let arr = []
      for(let item of this.middles) {
      	if(item.path === path) {
        	arr.push(item.cb)
        }
      }
      // 一级路由下面还有二级路由
      // 用洋葱模型串联所有匹配路由的处理函数
      this.compose(ctx, arr,next);
    }
  }
}
module.exports = Router

compose:用来组合中间件,让路由中间件按顺序执行

class Router {
    constructor() {
        this.middles = [];
    }
    //set,post等同理
    get(path,callback){
    	const layer = new Layer(path,callback)
    	this.middles.push(layer)
    }
    //arr为匹配的路由集合
    compose(ctx,arr,next){ 
        dispatch(index){
        	// 所有的路由处理完成之后,处理在路由中间件后面app.use注册的中间件
            if(index === lasts.length) return next();
            let route = arr[index];
            route(ctx,()=>{dispatch(index+1)})
        }
        dispatch(0)
    },
    return async (ctx, next) => {
      // 请求的路径
      let path = ctx.path;  
      // 和路径匹配的路由的处理函数
      let arr = []
      for(let item of this.middles) {
      	if(item.path === 'path') {
        	arr.push(item.cb)
        }
      }
      // 一级路由下面还有二级路由
      // 用洋葱模型串联所有匹配路由的处理函数
      this.compose(ctx, arr,next);
    }
}
module.exports = Router

关于其他

上面的router是简化版的koa-router,它只实现了koa-router中的一级路由,但是却是能说明koa-router的核心思想,koa-router中添加了use来注册二级路由,同时添加了很多包括重定向等其他逻辑处理

结语

koa-router中间件的原理基本就介绍完了,后面一起学习kao的其他中间件: