前言
Koa 是 Express 原班团队打造的下一代 Node.js Web 框架,核心仅1600+行代码,轻量简洁,原生支持 async/await,异步处理能力远优于 Express。
Koa 不内置路由、参数解析、静态文件等功能,全部依靠第三方中间件按需引入,自由度极高。本文整合基础使用、路由、参数解析、文件上传、静态服务、错误处理、洋葱模型、Express 对比,可直接当作开发查阅文档。
一、Koa 快速入门
1. 安装与基础服务搭建
安装依赖
npm install koa
最简服务示例
js
// app.js
const Koa = require('koa')
// 创建Koa实例
const app = new Koa()
// 注册中间件,参数 ctx(上下文)、next(放行函数)
app.use(async (ctx, next) => {
console.log('进入中间件')
await next() // 执行下一个中间件
console.log('离开中间件')
})
// 响应数据
app.use(ctx => {
// ctx.body 等价于 ctx.response.body,简化写法
ctx.body = 'Hello Koa'
})
// 监听端口
app.listen(8000, () => {
console.log('服务启动:http://localhost:8000')
})
核心概念说明
- ctx 上下文对象
Koa 将原生req、res封装到ctx,一次请求共用一个 ctx:
-
ctx.request:原生请求对象ctx.response:原生响应对象- 简写:
ctx.body=ctx.response.body、ctx.path=ctx.request.path
- next()
放行函数,调用后执行后续中间件;配合await实现洋葱模型异步流程。
二、路由处理(@koa/router)
Koa 无内置路由,需安装第三方 @koa/router 区分请求路径与请求方法。
1. 安装
bash
npm install @koa/router
2. 基础路由示例
js
const Koa = require('koa')
const Router = require('@koa/router')
const app = new Koa()
// 创建路由实例,prefix统一路由前缀
const userRouter = new Router({ prefix: '/users' })
// GET 请求
userRouter.get('/', ctx => {
ctx.body = '用户列表'
})
// POST 请求,创建资源状态码201
userRouter.post('/', ctx => {
ctx.status = 201
ctx.body = '创建用户成功'
})
// 动态路径参数 /users/100
userRouter.get('/:id', ctx => {
// ctx.params 获取动态参数
ctx.body = `当前用户ID:${ctx.params.id}`
})
// 注册路由中间件
app.use(userRouter.routes())
// 自动处理非法请求方法(405/501)
app.use(userRouter.allowedMethods())
app.listen(8000)
allowedMethods 作用
- 接口只实现 GET,客户端发起 PUT/DELETE:返回
405 Method Not Allowed - 客户端发起非常规请求(COPY/LINK):返回
501 Not Implemented
三、四种请求参数解析
1. URL 查询参数 query(?name=xxx)
地址:http://localhost:8000/login?username=张三&age=18
js
app.use(ctx => {
// ctx.query 自动解析查询字符串为对象
console.log(ctx.query.username, ctx.query.age)
ctx.body = ctx.query
})
2. 动态路径参数 params(/user/:id)
上文路由已演示,ctx.params.xxx 获取。
3. JSON / x-www-form-urlencoded 请求体(koa-bodyparser)
原生 Koa 无法解析 POST 请求体,安装 koa-bodyparser 解析 json、表单编码。
安装
npm install koa-bodyparser
使用代码
js
const Koa = require('koa')
const bodyParser = require('koa-bodyparser')
const app = new Koa()
// 注册解析中间件
app.use(bodyParser())
app.post('/login', ctx => {
// ctx.request.body 获取请求体
const { username, password } = ctx.request.body
ctx.body = { username, password }
})
4. form-data 文件/表单上传(koa-multer)
bodyparser 无法解析 form-data,使用 koa-multer,支持普通表单+文件上传。
安装
npm install koa-multer
1)普通form-data表单
js
const multer = require('koa-multer')
// 接收全部表单字段
const upload = multer()
app.use(upload.any())
app.post('/form', ctx => {
// 普通表单数据存在 ctx.req.body
console.log(ctx.req.body)
ctx.body = ctx.req.body
})
2)文件上传(保存到本地)
js
const multer = require('koa-multer')
const path = require('path')
// 配置文件存储位置与文件名
const storage = multer.diskStorage({
// 文件存放目录
destination: (req, file, cb) => cb(null, './uploads'),
// 自定义文件名:时间戳+原后缀
filename: (req, file, cb) => {
const ext = path.extname(file.originalname)
cb(null, Date.now() + ext)
}
})
const upload = multer({ storage })
// single('avatar') 接收单文件,表单字段名avatar
app.post('/upload', upload.single('avatar'), ctx => {
// 文件信息在 ctx.req.file
ctx.body = {
msg: '上传成功',
fileInfo: ctx.req.file
}
})
四、静态资源服务器(koa-static)
托管前端打包文件、图片、css/js 静态资源。
安装
arduino
npm install koa-static
示例代码
js
const Koa = require('koa')
const static = require('koa-static')
const app = new Koa()
// 托管当前目录下build文件夹,访问地址直接读取文件
app.use(static('./build'))
app.listen(8000, () => {
console.log('静态服务器启动')
})
访问 http://localhost:8000/index.html 自动读取 build 下的 index.html。
五、响应数据与状态码
1. ctx.body 支持所有类型
js
// 字符串
ctx.body = '文本内容'
// 对象/数组(自动转JSON)
ctx.body = { name: '小明', age: 20 }
ctx.body = [1, 2, 3]
// 空响应
ctx.body = null
2. 自定义状态码
js
// 资源创建成功
ctx.status = 201
// 无内容
ctx.status = 204
// 客户端错误
ctx.status = 400
// 接口不存在
ctx.status = 404
六、全局错误统一处理
通过 Koa 内置事件监听捕获全局异常,统一返回错误格式。
js
const Koa = require('koa')
const app = new Koa()
// 业务中间件主动抛出错误
app.use(async ctx => {
try {
throw new Error('服务器内部异常')
} catch (err)
// 手动触发error事件
ctx.app.emit('error', err, ctx)
}
})
// 全局错误监听
app.on('error', (err, ctx) => {
console.error('错误日志:', err.message)
ctx.status = 500
ctx.body = {
code: 500,
msg: err.message
}
})
app.listen(8000)
七、Koa 核心机制:洋葱模型
执行规则
中间件按照先进后出执行,像剥洋葱:
- 请求从上到下依次执行中间件
next()前代码 - 所有中间件执行完毕后,从下往上执行
next()后代码
示例代码直观演示
js
const Koa = require('koa')
const app = new Koa()
app.use(async (ctx, next) => {
console.log('中间件1:进入')
await next()
console.log('中间件1:离开')
})
app.use(async (ctx, next) => {
console.log('中间件2:进入')
await next()
console.log('中间件2:离开')
})
app.use(ctx => {
console.log('路由处理')
ctx.body = 'ok'
})
app.listen(8000)
输出顺序
中间件1:进入
中间件2:进入
路由处理
中间件2:离开
中间件1:离开
优势:异步代码配合 await 执行顺序完全可控,解决 Express 异步中间件执行混乱问题。
八、Koa vs Express 核心区别
| 对比维度 | Express | Koa2 |
|---|---|---|
| 架构 | 大而全,内置路由、静态服务 | 极简内核,所有功能依赖第三方中间件 |
| 异步处理 | 回调函数,异步流程难控制 | 原生 async/await,洋葱模型流程清晰 |
| 请求响应 | 分开 req / res | 统一封装 ctx 上下文 |
| 中间件机制 | 线性流水模型 | 洋葱模型(先进后出) |
| 内置API | 提供 app.get / app.post 路由 | 无内置路由,必须使用 koa-router |
九、完整项目基础模板(可直接复制使用)
js
const Koa = require('koa')
const Router = require('@koa/router')
const bodyParser = require('koa-bodyparser')
const static = require('koa-static')
const multer = require('koa-multer')
// 初始化
const app = new Koa()
const router = new Router({ prefix: '/api' })
const upload = multer({ dest: './uploads' })
// 全局中间件
app.use(bodyParser())
app.use(static('./static'))
// 业务接口
router.get('/user', ctx => {
ctx.body = { code: 200, data: { name: '测试用户' } }
})
router.post('/login', ctx => {
const data = ctx.request.body
ctx.body = { code: 200, data }
})
router.post('/upload', upload.single('file'), ctx => {
ctx.body = { code: 200, msg: '上传成功', file: ctx.req.file }
})
// 注册路由
app.use(router.routes()).use(router.allowedMethods())
// 全局错误处理
app.on('error', (err, ctx) => {
ctx.status = 500
ctx.body = { code: 500, msg: err.message }
})
// 启动服务
app.listen(8000, () => {
console.log('Koa服务运行在 8000 端口')
})
总结
- Koa 核心:
ctx上下文 +next()洋葱中间件模型; - 路由、参数解析、静态资源、文件上传全部依赖第三方中间件;
- 原生支持
async/await,异步代码比 Express 更易维护; - 开发固定流程:初始化Koa实例 → 注册全局中间件 → 编写路由 → 全局错误捕获 → 监听端口。