简介
koa是基于node开发的一个服务端框架,功能同express,但更小巧简单。
官方仓库地址:https://github.com/koajs/koa
创建项目
创建文件夹nodeKoa,执行以下脚本
javascript
npm init -y
npm i koa
npm i nodemon
基础示例
创建一个服务器
命令行输入
javascript
nodemon app.js
打开浏览器,输入http:localhost:3000即可看到效果
路由
koa没有提供路由模块,我们可以借助其内置的ctx.path获取其请求路径,自己做出判断
javascript
//创建一个请求
app.use( ctx => {
const path = ctx.path
if(path == "/"){
ctx.body = "这是首页"
}else if( path == "/foo"){
ctx.body = "这是详情页"
}else{
ctx.body = "404"
}
})
但是,这种方式还是比较麻烦的,我们使用它的官方route插件
javascript
npm install @koa/router
基础示例
javascript
/**
* 使用koa启动一个HTTP服务
*/
const Koa = require("koa")
const Router = require("@koa/router")
//创建实例
const app = new Koa()
const router = new Router()
router.get("/",ctx => {
ctx.body = '这是首页'
})
//路由挂载
app
.use(router.routes())
.use(router.allowedMethods());
app.listen(3000, () => {
console.log("服务运行在:http:localhost:3000");
})
路由模块的写法和expresss几乎是一致的
静态资源托管
如果网站提供静态资源(图片、字体什么的),如果为他们单独写一个路由很麻烦也没有必要。koa-stati模块封装了这部分请求
安装
javascript
npm install koa-static
我们在根目录创建一个public文件夹,里面放一张图片,然后直接访问里面的内容

可以发现,资源文件无法直接访问,我们创建一个静态资源目录
javascript
/**
* 使用koa启动一个HTTP服务
*/
const Koa = require("koa")
const Router = require("@koa/router")
//引入静态资源插件
const static = require("koa-static")
//创建实例
const app = new Koa()
//建立静态托管目录
app.use(static("./public"))
const router = new Router()
router.get("/",ctx => {
ctx.body = '这是首页'
})
//路由挂载
app
.use(router.routes())
.use(router.allowedMethods());
app.listen(3000, () => {
console.log("服务运行在:http:localhost:3000");
})
核心代码
javascript
//引入静态资源插件
const static = require("koa-static")
//建立静态托管目录
app.use(static("./public"))
这时,可以发现资源已经可以被正常访问了

我们目前的路径是相对路径,这是不安全的,我们应该使用绝对路径.
javascript
const path = require('path')
//建立静态托管目录
app.use(static(path.join(__dirname,"./public")))
虚拟路径
资源的目录或中间件可以设置成虚拟路径,需要使用官方的mount中间件
安装
javascript
npm install koa-mount
使用
javascript
const mount = require('koa-mount')
//建立静态托管目录
app.use( mount('/public',static(path.join(__dirname,"./public"))))
路由重定向
请求bar路径,重定向到boo
javascript
router.get('/bar',ctx => {
//重定向针对的同步请求
ctx.redirect('/boo')
)
中间件
koa最大的特色,就是中间件.为了理解中间件.我们先看一下logger(日志功能)的实现
- 先进后出
- 最外层首先执行
- 调用next,把执行权交给下一个中间件最内层的中间件最后执行

logger功能
javascript
/**
* 使用koa启动一个HTTP服务
*/
const Koa = require("koa")
//创建实例
const app = new Koa()
const one = (ctx,next) => {
console.log(">>> one");
next()
console.log("<<< one");
}
const two = (ctx,next) => {
console.log(">>> two");
next()
console.log("<<< two");
}
const three = (ctx,next) => {
console.log(">>> three");
next()
console.log("<<< three");
}
app.use(one)
app.use(two)
app.use(three)
app.listen(3000, () => {
console.log("服务运行在:http:localhost:3000");
})
输出结果
javascript
>>> one
>>> two
>>> three
<<< three
<<< two
<<< one
异步中间件
javascript
/**
* 使用koa启动一个HTTP服务
*/
const Koa = require("koa")
//创建实例
const app = new Koa()
const fs = require('fs')
const util = require("util")
app.use( async (ctx ,next) => {
const asyReadFile = util.promisify(fs.readFile)
const data = await asyReadFile("./index.html","utf8")
ctx.body = data
})
app.listen(3000, () => {
console.log("服务运行在:http//:localhost:3000");
})

除了在回调函数里指定类型,我们也可以在ctx里直接指定返回的类型
javascript
app.use( async (ctx ,next) => {
const asyReadFile = util.promisify(fs.readFile)
const data = await asyReadFile("./index.html")
ctx.type = "html"
ctx.body = data
})
Koa的中间件合并
当有多个中间件时,我们一个个进行挂载是非常低效的,我们可以使用中间件合并功能。
安装
npm install koa-compose
示例
app.use = compose([a1, a2, a3, ...])
中间件异常处理
正常情况,我们捕获一个错误可能会这么写代码
const Koa = require("koa")
//创建实例
const app = new Koa()
app.use( ctx => {
try {
JSON.parse("dsssssss")
ctx.body = "hello koa"
}catch(err){
ctx.response.status = 500
ctx.response.body = "服务端内部错误"
}
})
app.listen(3000, () => {
console.log("服务运行在:http://localhost:3000");
})

koa也给我们提供了内置函数简化500的错误响应
app.use( ctx => {
try {
JSON.parse("dsssssss")
ctx.body = "hello koa"
}catch(err){
ctx.throw(500)
}
})

对于多个异常,我们可以借助koa的洋葱模型进行捕获,用最外层的中间件进行异常捕获,内层的中间件异常最终全部会被koa最外层的中间件所捕获。
const Koa = require("koa");
//创建实例
const app = new Koa();
app.use(async (ctx, next) => {
try {
await next();
} catch (err) {
console.log(111);
ctx.response.status = 500;
ctx.body = "服务器内部错误";
}
});
app.use((ctx) => {
console.log(222);
JSON.parse("dsssssss");
ctx.body = "hello koa";
});
app.listen(3000, () => {
console.log("服务运行在:http://localhost:3000");
});
最外层的中间件函数必须写成async的形式,不然异常不会被捕获进去