洋葱模型

 

 

官网例子:

const Koa = require('koa');
const app = new Koa();

// logger
app.use(async (ctx, next) => {
  await next();
  const rt = ctx.response.get('X-Response-Time');
  console.log(`${ctx.method} ${ctx.url} - ${rt}`);
});

// x-response-time
app.use(async (ctx, next) => {
  const start = Date.now();
  await next();
  const ms = Date.now() - start;
  ctx.set('X-Response-Time', `${ms}ms`);
});

// response
app.use(async ctx => {
  ctx.body = 'Hello World';
});

app.listen(3000);

根据中间件的执行顺序,我们可以得到一下步骤:

1.logger中间件 执行了 await next()将执行权移交给了下一个中间件x-response-time
2.x-response-time中间件 记录了当前的时间,把执行权移交给了下一个中间件response
3.response中间件 返回了’Hello World’,把执行权还给了x-response-time
4.x-response-time 记录了当前时间 - 执行开始时间,并在respones header中记录下来,把执行权移交给了logger中间件
5.logger中间件在response中获取到X-Response-Time,并打印相关结果。

完整代码

const http = require('http');

// 组合中间件
function compose(middlewareList) {
    return function (ctx) {
        function dispatch(i) {
            const fn = middlewareList[i]
            try {
                return Promise.resolve(
                    fn(ctx, dispatch.bind(null, i + 1))
                )
            } catch (err) {
                return Promise.reject(err)
            }
        }
        return dispatch(0)
    }
}

class koaMiddleWare {
    constructor() {
        this.middlewareList = []
    }

    // 核心方法
    use(fn) {
        this.middlewareList.push(fn)
        return this
    }

    // 处理中间件的 http 请求
    handleRequest(ctx, middleWare) {
        // 这个 middleWare 就是 compose 函数返回的 fn
        // 执行 middleWare(ctx) 其实就是执行中间件函数,然后再用 Promise.resolve 封装并返回
        return middleWare(ctx)
    }

    // 将 req res 组合成为 ctx
    createContext(req, res) {
        // 简单模拟 koa 的 ctx ,不管细节了
        const ctx = {
            req,
            res
        }
        return ctx
    }

    callback() {
        const fn = compose(this.middlewareList)

        return (req, res) => {
            const ctx = this.createContext(req, res)
            return this.handleRequest(ctx, fn)
        }
    }

    listen(...args) {
        const server = http.createServer(this.callback())
        return server.listen(...args);
    }
}

module.exports = koaMiddleWare

 

posted on 2021-01-16 14:16  Jack·zhou  阅读(135)  评论(0编辑  收藏  举报