前言

广义中间件,间接中间件方式

  • 不直接提供中间件
  • 通过间接方式提供了中间件,最常见的是间接中间件子中间件
  • 间接被 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

    1. ## 安装依赖
    2. npm i
    3. ## 执行 demo
    4. npm run start
    5. ## 最后启动chrome浏览器访问
    6. ## http://127.0.0.1:3000/index
    7. ## http://127.0.0.1:3000/post
    8. ## http://127.0.0.1:3000/list
    9. ## http://127.0.0.1:3000/item

    解读

    1. const methods = [
    2. 'GET',
    3. 'PUT',
    4. 'PATCH',
    5. 'POST',
    6. 'DELETE'
    7. ];
    8. class Layer {
    9. constructor(path, methods, middleware, opts) {
    10. this.path = path;
    11. this.methods = methods;
    12. this.middleware = middleware;
    13. this.opts = opts;
    14. }
    15. }
    16. class Router {
    17. constructor(opts = {}) {
    18. this.stack = [];
    19. }
    20. register(path, methods, middleware, opts) {
    21. let route = new Layer(path, methods, middleware, opts);
    22. this.stack.push(route);
    23. return this;
    24. }
    25. routes() {
    26. let stock = this.stack;
    27. return async function(ctx, next) {
    28. let currentPath = ctx.path;
    29. let route;
    30. for (let i = 0; i < stock.length; i++) {
    31. let item = stock[i];
    32. if (currentPath === item.path && item.methods.indexOf(ctx.method) >= 0) {
    33. route = item.middleware;
    34. break;
    35. }
    36. }
    37. if (typeof route === 'function') {
    38. route(ctx, next);
    39. return;
    40. }
    41. await next();
    42. };
    43. }
    44. }
    45. methods.forEach(method => {
    46. Router.prototype[method.toLowerCase()] = Router.prototype[method] = function(path, middleware) {
    47. this.register(path, [method], middleware);
    48. };
    49. });
    50. module.exports = Router;

    使用

    1. const Koa = require('koa');
    2. const Router = require('./index');
    3. const app = new Koa();
    4. // 初始化路由实例
    5. const router = new Router();
    6. // 注册路由请求信息缓存到实例中
    7. router.get('/index', async ctx => { ctx.body = 'index page'; });
    8. router.get('/post', async ctx => { ctx.body = 'post page'; });
    9. router.get('/list', async ctx => { ctx.body = 'list page'; });
    10. router.get('/item', async ctx => { ctx.body = 'item page'; });
    11. // 路由实例输出父中间件 router.routes()
    12. app.use(router.routes());
    13. app.use(async ctx => {
    14. ctx.body = '404';
    15. });
    16. app.listen(3000);
    17. console.log('listening on port 3000');

    附录

    参考

  • https://github.com/alexmingoia/koa-router