首页 / Node.js 教程 / koa 入门

Node.js 教程

koa 入门

本教程共 76 篇 · 第 44 篇 · 更新于 2026-07-25 · 约 4 分钟阅读

Node.jskoa中间件洋葱模型Web框架

44. koa 入门

本节目标:koa 最小应用、洋葱模型中间件与 Express 的本质区别。

Express 用久了,你会发现回调和中间件的写法有时候让人头疼。Koa 是 Express 原班人马打造的下一代 Web 框架,核心卖点就一个:用 async/await 彻底告别回调地狱。这一章我们搭一个最小 koa 应用,搞清楚它的中间件机制和 Express 的本质区别。

安装与最小应用

koa 本身非常轻量,核心代码不到 2000 行。新建项目:

mkdir hello-koa && cd hello-koa
npm init -y
npm install koa

package.json 里加上 "type": "module",全程用 ESM:

{
  "name": "hello-koa",
  "type": "module",
  "dependencies": {
    "koa": "^2.15.3"
  }
}

创建 app.mjs

import Koa from 'koa';

const app = new Koa();

app.use(async (ctx, next) => {
  await next();
  ctx.response.type = 'text/html';
  ctx.response.body = '<h1>Hello Koa!</h1>';
});

app.listen(3000);
console.log('app started at port 3000...');

运行 node app.mjs,浏览器访问 http://localhost:3000,看到标题就说明跑通了。

Note

koa 2.x 要求 Node.js v7.6+(支持原生 async/await)。我们教程基准是 v24 LTS,完全没压力。

ctx 是什么

koa 把 Node.js 原生的 reqres 包进了一个叫 ctx(Context)的对象里。你可以把它想成「一次 HTTP 请求的上下文信封」,所有和这次请求有关的信息都装在里面。

常用简写:

  • ctx.url === ctx.request.url
  • ctx.method === ctx.request.method
  • ctx.body === ctx.response.body
  • ctx.status === ctx.response.status

这些简写给代码省了不少字符,实际项目中基本都是用简写版。

洋葱模型:中间件的执行顺序

koa 的中间件机制和 Express 最大的不同在于执行顺序。Express 是线性管道,进去就往前传;koa 是洋葱模型,先进去的中间件可以先执行后半段。

看个例子就懂:

app.use(async (ctx, next) => {
  console.log('>> 第一层:进入');
  await next();
  console.log('<< 第一层:离开');
});

app.use(async (ctx, next) => {
  console.log('>> 第二层:进入');
  await next();
  console.log('<< 第二层:离开');
});

app.use(async (ctx, next) => {
  console.log('>> 第三层:核心处理');
  ctx.body = 'Hello';
});

控制台输出:

>> 第一层:进入
>> 第二层:进入
>> 第三层:核心处理
<< 第二层:离开
<< 第一层:离开

像剥洋葱一样,先一层层进去,再一层层出来。这个特性在做日志、统计耗时、异常处理时特别好用:

app.use(async (ctx, next) => {
  const start = Date.now();
  await next();
  const ms = Date.now() - start;
  console.log(`${ctx.method} ${ctx.url} - ${ms}ms`);
});

和 Express 的对比

特性Expresskoa
中间件风格回调函数 (req, res, next)async 函数 (ctx, next)
执行顺序线性,不返回洋葱模型,可返回
错误处理手动 next(err)自动 try/catch + 全局监听
包体积~60KB(核心)~20KB(核心)
路由内置@koa/router
body 解析内置部分@koa/bodyparser

Express 开箱即用,生态更广;koa 更精简,对 async/await 的支持更自然。如果你喜欢自己组装工具链,koa 是更好的选择;如果你想快速搭项目,Express 依然很香。

全局错误捕获

koa 有一个 app.on('error', ...) 事件,可以集中处理所有中间件抛出的异常:

app.on('error', (err, ctx) => {
  console.error('server error', err.message);
});

app.use(async (ctx, next) => {
  // 任意中间件抛出异常都会被上面的监听器捕获
  if (ctx.url === '/boom') {
    throw new Error('something went wrong');
  }
  await next();
});
Warning

koa 只会捕获异步中间件里的错误。如果你在中间件里写了同步代码抛错却没包 try/catch,进程可能直接崩掉。养成 async 函数 + await 的习惯,基本能避开这个坑。