博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
koa框架会用也会写—(koa-router)
阅读量:4087 次
发布时间:2019-05-25

本文共 5423 字,大约阅读时间需要 18 分钟。

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()).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-router的原理

既然koa-router也是大的中间件,里面拥有许多小的中间件,那么里面必然也需要用到洋葱模型,洋葱模型的特点:

  • middles:存放中间件的容器,用来存放注册的中间件
  • get(path,fn):用来注册中间件,往middles中存放,由于是路由中间件这里多了一个参数path
  • compose():用来组合中间件,让路由中间件按顺序执行
  • routes():用来将koa-router中间件注册到app的中间件上,主要作用是调用路由中间件匹配请求的路径ctx.path

如果对于中间件和洋葱模型有疑问的,可以参考

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复制代码

关于其他

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

结语

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

作者:梦想攻城狮
链接:https://juejin.im/post/5bad90b8f265da0aac6fe9ee
来源:掘金
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

你可能感兴趣的文章
JavaScript实现DOM树的深度优先遍历和广度优先遍历
查看>>
webpack4 中的 React 全家桶配置指南,实战!
查看>>
react 设置代理(proxy) 实现跨域请求
查看>>
通过试题理解JavaScript
查看>>
webpack的面试题总结
查看>>
实践这一次,彻底搞懂浏览器缓存机制
查看>>
Koa2教程(常用中间件篇)
查看>>
React Hooks 完全指南
查看>>
React16常用api解析以及原理剖析
查看>>
教你发布你npm包
查看>>
nvm 和 nrm 的安装与使用
查看>>
React Hooks 一步到位
查看>>
React Redux常见问题总结
查看>>
前端 DSL 实践指南
查看>>
ReactNative: 自定义ReactNative API组件
查看>>
cookie
查看>>
总结vue知识体系之实用技巧
查看>>
PM2 入门
查看>>
掌握 TS 这些工具类型,让你开发事半功倍
查看>>
前端如何搭建一个成熟的脚手架
查看>>