{"id":18825024,"url":"https://github.com/lulusir/build-your-own-koa","last_synced_at":"2026-01-20T19:30:16.756Z","repository":{"id":227744854,"uuid":"622775491","full_name":"lulusir/build-your-own-Koa","owner":"lulusir","description":null,"archived":false,"fork":false,"pushed_at":"2023-04-03T03:18:36.000Z","size":3,"stargazers_count":1,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2024-12-30T04:49:05.876Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/lulusir.png","metadata":{"files":{"readme":"readme.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null}},"created_at":"2023-04-03T03:18:01.000Z","updated_at":"2023-04-15T02:06:02.000Z","dependencies_parsed_at":"2024-03-14T23:50:32.067Z","dependency_job_id":"a2872ea2-cd2c-42b9-8872-1082379c6d5e","html_url":"https://github.com/lulusir/build-your-own-Koa","commit_stats":null,"previous_names":["lulusir/build-your-own-koa"],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/lulusir%2Fbuild-your-own-Koa","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/lulusir%2Fbuild-your-own-Koa/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/lulusir%2Fbuild-your-own-Koa/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/lulusir%2Fbuild-your-own-Koa/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/lulusir","download_url":"https://codeload.github.com/lulusir/build-your-own-Koa/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":239763665,"owners_count":19692802,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-11-08T00:58:12.410Z","updated_at":"2026-01-20T19:30:16.712Z","avatar_url":"https://github.com/lulusir.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"觉得有帮助的同学记得给个star，谢谢\n# 手把手教你实现一个Koa\n## koa是什么\n\nKoa 是一个基于 Node.js 的 Web 服务器库，其核心思想是中间件模式。相比其他框架（如 Express），Koa 更加轻量级、简洁、易扩展，且支持异步操作。\n\n在 Koa 中，中间件是一个函数，其可以访问 HTTP 请求和响应对象，以及 next 函数，通过调用 next 函数可以将控制权交给下一个中间件。Koa 中间件的执行顺序与注册顺序相同，可以使用 async/await 实现异步操作。\n\n关于中间件模式，之前我写过一篇文章介绍如何实现，不了解的可以查看[使用Typescript实现中间件模式，顺便发了个npm包](https://juejin.cn/post/7174802901766766650)\n\n接下来我们来实现一个自己的 Koa，当然，这里只包含简单的核心功能，即一个基于中间件模式的服务器。\n\n## 中间件\n首先是核心的中间件代码，功能就不过多介绍了，不了解的可以查看之前的文章[使用Typescript实现中间件模式，顺便发了个npm包](https://juejin.cn/post/7174802901766766650)\n\n另外，这个中间件也单独发了 npm 包，你可以使用在你需要的地方：\n```bash\nnpm install @lujs/middleware\n```\n```typescript\ntype IMiddlewareNextFunction = () =\u003e Promise\u003cany\u003e;\n\ninterface IMiddleware\u003cCTX\u003e {\n  (context: CTX, next: IMiddlewareNextFunction): any | Promise\u003cany\u003e;\n}\n\nclass MiddlewareRunner\u003cCTX\u003e {\n  middleware: IMiddleware\u003cCTX\u003e[] = [];\n\n  middlewareCurrent = 0;\n\n  use = (middleware: IMiddleware\u003cCTX\u003e) =\u003e {\n    this.middleware.push(middleware);\n  };\n\n  run = async (context: CTX) =\u003e {\n    let err: Error | null = null;\n    this.middlewareCurrent = 0;\n    const next = async () =\u003e {\n      const middleware = this.middleware[this.middlewareCurrent];\n      this.middlewareCurrent += 1;\n      if (typeof middleware === 'function') {\n        try {\n          const p = middleware(context, next);\n          if (p instanceof Promise) {\n            await p;\n          }\n        } catch (e) {\n          // 运行中间件出错就执行下一个\n          await next();\n          err = e as Error;\n        }\n      }\n    };\n    await next();\n\n    if (err) {\n      throw err;\n    }\n    return context;\n  };\n}\n```\n## Context\n接下来声明我们的context，这个context会在每个中间件中流转，在koa中对context做了封装，我们这里为了方便演示，直接使用http的req和res作为context的内容；这里的body则是最后响应到http接口的body\n```typescript\ninterface Context {\n  req: http.IncomingMessage;\n  res: http.ServerResponse;\n  body?: any;\n}\n```\n## core核心代码\n其实核心代码就这几行，Koa类，内置一个MiddlewareRunner，用来记录和运行中间件；\n\nuse方法则是注册中间件\n\nlisten方法则是启动一个http服务，然后运行内置的MiddlewareRunner\n```typescript\nclass Koa {\n  runner = new MiddlewareRunner\u003cContext\u003e();\n\n  listen(...args: ServerListenParams) {\n    const server = http.createServer(async (req, res) =\u003e {\n      const ctx: Context = {\n        req,\n        res,\n      };\n      await this.runner.run(ctx).catch((e) =\u003e this._errorHandler(e, ctx));\n      ctx.res.end(ctx.body);\n    });\n\n    console.log('listen...', args[0]);\n\n    server.listen(...args);\n  }\n\n  _errorHandler: (error: Error, ctx: Context) =\u003e Promise\u003cvoid\u003e = async () =\u003e {};\n\n  useError(hander: (error: Error, ctx: Context) =\u003e Promise\u003cvoid\u003e) {\n    this._errorHandler = hander;\n  }\n\n  use(middleware: IMiddleware\u003cContext\u003e) {\n    this.runner.use(middleware);\n  }\n}\n```\n\n## 实现中间件的错误处理\n上面的代码中，我们已经实现了一个基于中间件模式的 Koa，但是还没有加入错误处理的功能。在实际开发中，错误处理是非常重要的一部分。为了方便演示，我们先编写一个会出现错误的中间件，然后加入错误处理代码。这里我们定义一个名为 m2 的中间件，在这个中间件中，我们主动触发一个错误\n```typescript\nconst m2: IMiddleware\u003cContext\u003e = async (_ctx: Context, next) =\u003e {\n  throw new Error('出错啦！');\n};\n\nconst errorHandler: IMiddleware\u003cContext\u003e = async (ctx: Context, next) =\u003e {\n  try {\n    await next();\n  } catch (err) {\n    console.error(err);\n    ctx.body = '出错啦！';\n  }\n};\n\n```\n## 运行\n接下来我们把自己的koa跑起来，然后发一个请求看看是否成功响应\n```typescript\nconst m1: IMiddleware\u003cContext\u003e = async (ctx: Context, next) =\u003e {\n  ctx.body = 'success';\n  await next();\n};\n\nconst koa = new Koa();\n\nkoa.useError(errorHandler); // 插入错误处理中间件\nkoa.use(m1);\nkoa.use(m2);\n\nconst port = 3101;\nkoa.listen(port, () =\u003e {\n  setTimeout(() =\u003e {\n    http\n      .get(`http://localhost:${port}/`, (res) =\u003e {\n        let rawData = `response from http://localhost:${port}/: `;\n        res.on('data', (chunk) =\u003e {\n          rawData += chunk;\n        });\n        res.on('end', () =\u003e {\n          console.log(rawData);\n        });\n      })\n      .on('error', (e) =\u003e {\n        console.error(`Got error: ${e.message}`);\n      });\n  }, 1000);\n});\n\n\n\n```\n[中间件源码](https://github.com/lulusir/middleware)，期待你的star，谢谢！\n\n\n\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Flulusir%2Fbuild-your-own-koa","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Flulusir%2Fbuild-your-own-koa","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Flulusir%2Fbuild-your-own-koa/lists"}