用法

  1. const Koa = require("koa")
  2. const app = new Koa()
  3. //middleware
  4. app.use(async (ctx, next) => {
  5. const start = Date.now()
  6. await next()
  7. const ms = Date.now() - start
  8. console.log(`${ctx.method} ${ctx.url} - ${ms}ms`)
  9. })
  10. // response
  11. app.use(ctx => {
  12. ctx.body = "Hello Koa"
  13. })
  14. app.listen(3000)

创建应用程序

  1. function listen() {
  2. const server = http.createServer(callback())
  3. return server.listen()
  4. }
  5. function callback() {
  6. // 组织中间件
  7. const fn = compose(middleware)
  8. // 监听异常处理
  9. on("error", onerror)
  10. // 每次请求调用该函数
  11. const handleRequest = (req, res) => {
  12. // 接收两个参数 原始node的 req,res 对象,http上的类生成的实例
  13. // 生成上下文对象
  14. const ctx = createContext(req, res)
  15. return handleRequest(ctx, fn)
  16. }
  17. return handleRequest
  18. }
  19. function handleRequest(ctx, fnMiddleware) {
  20. const res = ctx.res
  21. // 默认状态码为404
  22. res.statusCode = 404
  23. // 中间件执行完毕之后 采用默认的 错误 与 成功 的处理方式
  24. const onerror = err => ctx.onerror(err)
  25. const handleResponse = () => respond(ctx)
  26. onFinished(res, onerror)
  27. return fnMiddleware(ctx)
  28. .then(handleResponse)
  29. .catch(onerror)
  30. }

生成上下文对象

  1. function createContext(req, res) {
  2. // this.context 会定义属性代理、方法代理
  3. // 属性代理 access (context, response|request, header) Object.defineProperty
  4. // 方法代理 method (context, response|request, send) 通过返回新函数
  5. const context = Object.create(this.context)
  6. // 自定义request、response对象
  7. const request = (context.request = Object.create(this.request))
  8. const response = (context.response = Object.create(this.response))
  9. context.app = request.app = response.app = this
  10. context.req = request.req = response.req = req
  11. context.res = request.res = response.res = res
  12. request.ctx = response.ctx = context
  13. request.response = response
  14. response.request = request
  15. context.originalUrl = request.originalUrl = req.url
  16. context.state = {}
  17. return context
  18. }

中间件实现原理

定义compose函数,返回的函数每次请求都会被调用,注册的中间件每一次请求都会执行

function compose(middleware) {
  return function(context) {
    return dispatch(0)
    // 返回函数内部定义next函数,该函数接收自增的标识符,每次执行加1,初始为0,通过该参数取出队列中的中间件函数执行,
    // 并且把上下文对象以及next函数自身传给中间件函数,这样中间件函数就可以实现业务逻辑,并且主动调用next函数,消费队列里的中间件,这样就实行了中间件
    function dispatch(i) {
      // 取出中间件
      let fn = middleware[i]
      if (!fn) return Promise.resolve()
      try {
        // 递归调用下一个中间件
        return Promise.resolve(fn(context, () => dispatch(i + 1)))
      } catch (err) {
        return Promise.reject(err)
      }
    }
  }
}