koa入门3-6

时间:2022-05-14 00:45:30

创建koa2工程

首先,我们创建一个目录​​hello-koa​​并作为工程目录用VS Code打开。然后,我们创建​​app.js​​,输入以下代码:

// 导入koa,和koa 1.x不同,在koa2中,我们导入的是一个class,因此用大写的Koa表示:
const Koa = require('koa');

// 创建一个Koa对象表示web app本身:
const app = new Koa();

// 对于任何请求,app将调用该异步函数处理请求:
app.use(async (ctx, next) => {
await next();
ctx.response.type = 'text/html';
ctx.response.body = '<h1>Hello, koa2!</h1>';
});

// 在端口3000监听:
app.listen(3000);
console.log('app started at port 3000...');

对于每一个http请求,koa将调用我们传入的异步函数来处理:

async (ctx, next) => {
await next();
// 设置response的Content-Type:
ctx.response.type = 'text/html';
// 设置response的内容:
ctx.response.body = '<h1>Hello, koa2!</h1>';
}

其中,参数​​ctx​​是由koa传入的封装了request和response的变量,我们可以通过它访问request和response,​​next​​是koa传入的将要处理的下一个异步函数。

上面的异步函数中,我们首先用​​await next();​​处理下一个异步函数,然后,设置response的Content-Type和内容。

由​​async​​标记的函数称为异步函数,在异步函数中,可以用​​await​​调用另一个异步函数,这两个关键字将在ES7中引入。

现在我们遇到第一个问题:koa这个包怎么装,​​app.js​​才能正常导入它?

方法一:可以用npm命令直接安装koa。先打开命令提示符,务必把当前目录切换到​​hello-koa​​这个目录,然后执行命令:

C:\...\hello-koa> npm install koa@2.0.0

npm会把koa2以及koa2依赖的所有包全部安装到当前目录的node_modules目录下。

方法二:在​​hello-koa​​这个目录下创建一个​​package.json​​,这个文件描述了我们的​​hello-koa​​工程会用到哪些包。完整的文件内容如下:

{
"name": "hello-koa2",
"version": "1.0.0",
"description": "Hello Koa 2 example with async",
"main": "app.js",
"scripts": {
"start": "node app.js"
},
"keywords": [
"koa",
"async"
],
"author": "Michael Liao",
"license": "Apache-2.0",
"repository": {
"type": "git",
"url": "https://github.com/michaelliao/learn-javascript.git"
},
"dependencies": {
"koa": "2.0.0"
}
}

其中,​​dependencies​​描述了我们的工程依赖的包以及版本号。其他字段均用来描述项目信息,可任意填写。

然后,我们在​​hello-koa​​目录下执行​​npm install​​就可以把所需包以及依赖包一次性全部装好:

C:\...\hello-koa> npm install

很显然,第二个方法更靠谱,因为我们只要在​​package.json​​正确设置了依赖,npm就会把所有用到的包都装好。

注意,任何时候都可以直接删除整个​​node_modules​​目录,因为用​​npm install​​命令可以完整地重新下载所有依赖。并且,这个目录不应该被放入版本控制中。

现在,我们的工程结构如下:

hello-koa/
|
+- .vscode/
| |
| +- launch.json <-- VSCode 配置文件
|
+- app.js <-- 使用koa的js
|
+- package.json <-- 项目描述文件
|
+- node_modules/ <-- npm安装的所有依赖包

紧接着,我们在​​package.json​​中添加依赖包:

"dependencies": {
"koa": "2.0.0"
}

然后使用​​npm install​​命令安装后,在VS Code中执行​​app.js​​,调试控制台输出如下:

node --debug-brk=40645 --nolazy app.js 
Debugger listening on port 40645
app started at port 3000...

我们打开浏览器,输入​​http://localhost:3000​​,即可看到效果:

koa入门3-6

还可以直接用命令​​node app.js​​在命令行启动程序,或者用​​npm start​​启动。​​npm start​​命令会让npm执行定义在​​package.json​​文件中的start对应命令:

"scripts": {
"start": "node app.js"
}

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()​​注册的async函数,并传入​​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;
}
});