koa 入门
本教程共 76 篇 · 第 44 篇 · 更新于 2026-07-25 · 约 4 分钟阅读
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,看到标题就说明跑通了。
Notekoa 2.x 要求 Node.js v7.6+(支持原生 async/await)。我们教程基准是 v24 LTS,完全没压力。
ctx 是什么
koa 把 Node.js 原生的 req 和 res 包进了一个叫 ctx(Context)的对象里。你可以把它想成「一次 HTTP 请求的上下文信封」,所有和这次请求有关的信息都装在里面。
常用简写:
ctx.url===ctx.request.urlctx.method===ctx.request.methodctx.body===ctx.response.bodyctx.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 的对比
| 特性 | Express | koa |
|---|---|---|
| 中间件风格 | 回调函数 (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();
});
Warningkoa 只会捕获异步中间件里的错误。如果你在中间件里写了同步代码抛错却没包 try/catch,进程可能直接崩掉。养成 async 函数 + await 的习惯,基本能避开这个坑。