摘要 - 廖雪峰JavaScript教程
创建一个koa2工程
首先,我们创建一个test
目录,并在目录里面创建一个koa.js
文件,输入以下代码:
// 导入的是koa2,不是koa1,koa2是一个class类,所以大写。
const Koa = require('koa')
// 创建一个web app 实例
const app = new Koa()
// 对于任何请求,都执行该回调函数
app.use(async (ctx, next) => {
await next()
ctx.response.type = 'text/html'
ctx.response.body = '<h1> Hello Koa2 </h1>'
})
// 监听9000端口
app.listen(9000, () => {
console.log('Server is running and the port is 9000 ')
})
其中,参数ctx
是koa传入的封装了response
和resquest
的变量,next
是koa要处理的下一个异步函数。
上面的异步函数中,我们首先用await next( )
处理下一个异步函数,然后设置Content-Type
和内容。
由async
标记的函数称为异步函数,在异步函数中,可以用await
调用另一个异步函数,这两个关键字在ES7中引入。
注意:要是想运行上面的代码,请使用最新的node7以后的版本,因为低版本的node不支持async
和await
关键,或者你可以babel
进行转成es5进行运行。
koa middleware
让我们在仔细看下koa的执行逻辑。核心代码是:
app.use(async (ctx, next) => {
await next()
ctx.response.type = 'text/html'
ctx.response.body = '<h1> Hello Koa2 </h1>'
})
每收到一个http
请求,koa就会调用通过app.use()
注册的异步函数,并传入ctx
和next
参数。
我们可以对ctx
操作,并设置返回内容。但是为什么要调用await next()
?
原因是koa把很多async
函数组成一个处理链,每个async
函数都可以做一些自己的事情,然后用await next()
来调用下一个async
函数。我们把每个async
函数称为middleware
,这些middleware
可以组合起来,完成很多有用的功能。
例如,可以用以下3个middleware
组成处理链,依次打印日志,记录处理时间,输出HTML:
app.use(async (ctx, next) => {
console.log(`${ctx.request.method} ${ctx.request.url}`); // 打印URL
await next(); // 调用下一个middleware
});
app.use(async (ctx, next) => {
const start = new Date().getTime(); // 当前时间
await next(); // 调用下一个middleware
const ms = new Date().getTime() - start; // 耗费时间
console.log(`Time: ${ms}ms`); // 打印耗费时间
});
app.use(async (ctx, next) => {
await next();
ctx.response.type = 'text/html';
ctx.response.body = '<h1>Hello, koa2!</h1>';
});
middleware
的顺序很重要,也就是调用app.use()
的顺序决定了middleware
的顺序。
此外,如果一个middleware
没有调用await next()
,会怎么办?答案是后续的middleware
将不再执行了。这种情况也很常见,例如,一个检测用户权限的middleware
可以决定是否继续处理请求,还是直接返回403错误:
app.use(async (ctx, next) => {
if (await checkUserPermission(ctx)) {
await next();
} else {
ctx.response.status = 403;
}
});
理解了middleware
,我们就基本会用koa了!
最后注意ctx
对象有一些简写的方法,例如ctx.url
相当于ctx.request.url
,ctx.type
相当于ctx.response.type
。