koa-router 实现
前言
广义中间件,间接中间件方式
- 不直接提供中间件
- 通过间接方式提供了中间件,最常见的是
间接中间件
和子中间件
- 间接被
app.use()
加载 - 其他方式接入Koa切面
这里 广义中间件,间接中间件方式实现 最代表性是第三方实现的 koa-router
中间件,这里基于第三方中间件 koa-router
用最简单的方式实现 koa-router
最简单功能。
实现步骤
- 初始化路由实例
- 注册路由请求信息缓存到实例中
- 请求类型
- 请求path
- 对应的请求后操作
- 注册的路由操作就是子中间件
- 路由实例输出父中间件
- 返回一个父中间件
- 中间件里对每次请求进行遍历匹配缓存中注册的路由操作
- 匹配上请求类型,路径就执行对应路由子中间件
- app.use()路由实例返回的父中间件
实现源码
https://github.com/chenshenhai/koajs-design-note/tree/master/demo/chapter-06-01
## 安装依赖
npm i
## 执行 demo
npm run start
## 最后启动chrome浏览器访问
## http://127.0.0.1:3000/index
## http://127.0.0.1:3000/post
## http://127.0.0.1:3000/list
## http://127.0.0.1:3000/item
解读
const methods = [
'GET',
'PUT',
'PATCH',
'POST',
'DELETE'
];
class Layer {
constructor(path, methods, middleware, opts) {
this.path = path;
this.methods = methods;
this.middleware = middleware;
this.opts = opts;
}
}
class Router {
constructor(opts = {}) {
this.stack = [];
}
register(path, methods, middleware, opts) {
let route = new Layer(path, methods, middleware, opts);
this.stack.push(route);
return this;
}
routes() {
let stock = this.stack;
return async function(ctx, next) {
let currentPath = ctx.path;
let route;
for (let i = 0; i < stock.length; i++) {
let item = stock[i];
if (currentPath === item.path && item.methods.indexOf(ctx.method) >= 0) {
route = item.middleware;
break;
}
}
if (typeof route === 'function') {
route(ctx, next);
return;
}
await next();
};
}
}
methods.forEach(method => {
Router.prototype[method.toLowerCase()] = Router.prototype[method] = function(path, middleware) {
this.register(path, [method], middleware);
};
});
module.exports = Router;
使用
const Koa = require('koa');
const Router = require('./index');
const app = new Koa();
// 初始化路由实例
const router = new Router();
// 注册路由请求信息缓存到实例中
router.get('/index', async ctx => { ctx.body = 'index page'; });
router.get('/post', async ctx => { ctx.body = 'post page'; });
router.get('/list', async ctx => { ctx.body = 'list page'; });
router.get('/item', async ctx => { ctx.body = 'item page'; });
// 路由实例输出父中间件 router.routes()
app.use(router.routes());
app.use(async ctx => {
ctx.body = '404';
});
app.listen(3000);
console.log('listening on port 3000');