本文共 5423 字,大约阅读时间需要 18 分钟。
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());复制代码
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也是大的中间件,里面拥有许多小的中间件,那么里面必然也需要用到洋葱模型,洋葱模型的特点:
如果对于中间件和洋葱模型有疑问的,可以参考
class Router { constructor(){ this.middles=[]; }}module.exports = Router复制代码
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复制代码
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复制代码
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的其他中间件: