前言

广义中间件,间接中间件方式实现,还有一个官方的中间件 koa-mount ,让多个Koa.js子应用合并成一个父应用,用请求的前缀区分子应用。这里基于第三方中间件 koa-mount 用最简单的方式实现 koa-mount 最简单功能。

实现步骤

  • 使用过程
    • 初始化子应用Koa.js实例
    • 初始化父应用Koa.js实例
    • 处理子应用middleware属性,将所有中间件用koa-compose封装成一个子应用中间件
    • 用父应用app.use()加载处理后的子应用中间件
  • mount实现过程

    • 输入子应用的前缀和应用实例
    • 获取子应用的中间件集合middleware属性
    • 用koa-compose封装子应用的中间件集合
    • 返回一个父中间件
      • 父中间件里执行compose封装后的子中间件集合
      • 执行前把请求path子应用前缀去掉
      • 执行后把请求path子应用前缀还原到原始请求path
    • 父应用app.use子应用封装后父中间件,(compose封装的子应用所有中间件)

      实现源码

      https://github.com/chenshenhai/koajs-design-note/tree/master/demo/chapter-06-02
      1. ## 安装依赖
      2. npm i
      3. ## 执行 demo
      4. npm run start
      5. ## 最后启动chrome浏览器访问
      6. ## http://127.0.0.1:3000/app1
      7. ## http://127.0.0.1:3000/app1

      依赖

  • koa-compose

    解读

    1. const path = require('path');
    2. const compose = require('./compose');
    3. function mount(prefix, app) {
    4. let middleware = app.middleware;
    5. let middlewareStream = compose(middleware || []);
    6. if( prefix === '/' ) {
    7. return middlewareStream;
    8. }
    9. return async function( ctx, next ) {
    10. let mountPath = matchPath(ctx.path);
    11. if( !mountPath ) {
    12. return await next();
    13. }
    14. let originPath = ctx.path;
    15. ctx.path = mountPath;
    16. await middlewareStream(ctx, async () => {
    17. ctx.path = originPath;
    18. await next();
    19. ctx.path = mountPath
    20. });
    21. ctx.path = originPath;
    22. }
    23. function matchPath( originPath ) {
    24. if( originPath.indexOf(prefix) < 0 ) {
    25. return false;
    26. }
    27. const mountPath = originPath.replace(prefix, '') || '/';
    28. if( mountPath[0] !== '/' ) {
    29. return false;
    30. }
    31. return mountPath;
    32. }
    33. }
    34. module.exports = mount;

    使用

    1. const mount = require('./index');
    2. const Koa = require('koa');
    3. const app1 = new Koa();
    4. const app2 = new Koa();
    5. app1.use(async (ctx, next) => {
    6. await next()
    7. ctx.body = 'app 1'
    8. })
    9. app2.use(async (ctx, next) => {
    10. await next()
    11. ctx.body = 'app 2'
    12. })
    13. const app = new Koa()
    14. app.use(mount('/app1', app1))
    15. app.use(mount('/app2', app2))
    16. app.listen(3000)
    17. console.log('listening on port 3000');

    附录

    参考

  • https://github.com/koajs/mount