文章概述
本篇文章介绍koa2框架的使用。
koa历史
- 基于2.x
参考资料
- Koa GitHub地址:https://github.com/koajs/koa
安装koa
- npm安装koa到node_modules:
1 | $ npm install koa --save |
- js文件中引入:
1 | const Koa = require('koa'); |
koa概述
koa是Express的下一代基于Node.js的web框架,目前有1.x和2.0两个版本,此处基于2.x版本;
异步概念
koa2完全使用Promise并配合async来实现异步, koa可以把很多async函数组成一个处理链;
异步执行流程
每收到一个http请求,koa就会调用通过app.use()注册的async函数,并传入ctx和next参数,async函数内部,用await next()来调用下一个async函数,async函数按顺序用app.use()注册,next函数也是按注册顺序调用,如果一个async函数内没有调用await next(),则后续的async函数将不再执行。
1 | app.use(async (ctx, next) => { |
1 | 【async异步函数参数】 |
中间件
每个async函数称为middleware,这些middleware可以组合起来,完成很多有用的功能。
koa-bodyparser模块
详见:HTTP服务章节;
- koa-bodyparser库用来解析原始request请求,然后,把解析后的参数,绑定到ctx.request.body中。
- 在koa中,我们只需要给ctx.response.body赋值一个JavaScript对象,koa会自动把该对象序列化为JSON并输出到客户端。
- 非常适合编写rest-api;
处理url
使用koa-router路由来集中处理url.
koa原生处理
koa原生api可以处理url,来响应不同的请求,如下,但是当支持的请求越多就会越混乱;1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33// 导入koa
const Koa = require('koa');
// 创建一个Koa对象表示web app本身:
const app = new Koa();
app.use(async (ctx, next) => {
if (ctx.request.path === '/') {
ctx.response.body = 'index page';
} else {
await next();
}
});
app.use(async (ctx, next) => {
if (ctx.request.path === '/test') {
ctx.response.body = 'TEST page';
} else {
await next();
}
});
app.use(async (ctx, next) => {
if (ctx.request.path === '/error') {
ctx.response.body = 'ERROR page';
} else {
await next();
}
});
// 在端口3000监听:
app.listen(3000);
console.log('server on http://localhost:3000/');
koa-router
为了处理URL,我们需要引入koa-router这个middleware,让它负责处理URL映射,这样开发者不用每次都去调用await next(),而只需要关心请求的处理。
get请求
使用router.get(‘/path’, async fn)来注册一个GET请求。
参数
- 可以在请求路径中使用带变量的/hello/:name,变量可以通过ctx.params.name访问。
示例
1 | const Koa = require('koa'); |
post请求
请求参数
用post请求处理URL时,post请求通常会发送一个表单,或者JSON,它作为request的body发送,但是Node.js原始request对象、koa提供的request对象,都不提供解析request的body的功能。
koa-bodyparser库用来解析原始request请求,然后,把解析后的参数,绑定到ctx.request.body中。
- 安装koa-bodyparser库:
1 | $ npm install --save koa-bodyparser |
- 导入,在router.routes()之前调用:
1 | const bodyParser = require('koa-bodyparser'); |
示例
一个post请求登录的实例1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41const Koa = require('koa');
// 注意require('koa-router')返回的是函数:
const router = require('koa-router')();
const bodyParser = require('koa-bodyparser');
const app = new Koa();
// log request URL:
app.use(async (ctx, next) => {
console.log(`Process ${ctx.request.method} ${ctx.request.url}...`);
await next();
});
router.get('/', async (ctx, next) => {
ctx.response.body = `<h1>Index</h1>
<form action="/signin" method="post">
<p>Name: <input name="name" value="koa"></p>
<p>Password: <input name="password" type="password"></p>
<p><input type="submit" value="Submit"></p>
</form>`;
});
router.post('/signin', async (ctx, next) => {
var
name = ctx.request.body.name || '',
password = ctx.request.body.password || '';
console.log(`signin with name: ${name}, password: ${password}`);
if (name === 'koa' && password === '12345') {
ctx.response.body = `<h1>Welcome, ${name}!</h1>`;
} else {
ctx.response.body = `<h1>Login failed!</h1>
<p><a href="/">Try again</a></p>`;
}
});
app.use(bodyParser());
app.use(router.routes());
app.listen(3000);
console.log('server on http://localhost:3000/');
HTTP-API封装
- 创建controller文件夹,用来处理请求业务,包含hell.js和index.js文件;
- hello.js文件,处理hello页面相关请求:
1 | let fn_hello = async (ctx, next) => { |
- index.js登录页面处理登录相关请求:
1 | let fn_index = async (ctx, next) => { |
- controller.js文件,用于扫描controller目录里面的js请求处理文件;
1 | const fs = require('fs'); |
- app.js作为程序的入口:
1 | const Koa = require('koa'); |
REST-API
规范
编写REST API,实际上就是编写处理HTTP请求的async函数,不过,REST请求和普通的HTTP请求有几个特殊的地方:
- REST请求仍然是标准的HTTP请求,但是,除了GET请求外,POST、PUT等请求的body是JSON数据格式,请求的Content-Type为application/json;
- REST响应返回的结果是JSON数据格式,因此,响应的Content-Type也是application/json。
- REST请求只是一种请求类型和响应类型均为JSON的HTTP请求;
rest-url示例
- GET请求:获取所有Product的URL:
1 | GET /api/products |
- GET请求:id为123的Product的URL:
1 | GET /api/products/123 |
- GET请求:资源还可以按层次组织。例如,获取某个Product的所有评论,使用:
1 | GET /api/products/123/reviews |
- GET请求:当我们只需要获取部分数据时,可通过参数限制返回的结果集,例如,返回第2页评论,每页10项,按时间排序:
1 | GET /api/products/123/reviews?page=2&size=10&sort=time |
- POST请求: 新建一个Product,JSON数据参数包含在body中,URL如下:
1 | POST /api/products |
- PUT请求: 更新一个Product使用PUT请求,例如,更新id为123的Product,其URL如下:
1 | PUT /api/products/123 |
- DELETE请求:删除一个Product使用DELETE请求,例如,删除id为123的Product,其URL如下:
1 | DELETE /api/products/123 |
编写rest-api
这里使用koa-bodyparser模块库来让ctx.request.body直接访问解析后的JavaScript对象。
在koa中处理REST请求是非常简单的。bodyParser()这个middleware可以解析请求的JSON数据并绑定到ctx.request.body上,输出JSON时我们先指定ctx.response.type = ‘application/json’,然后把JavaScript对象赋值给ctx.response.body就完成了REST请求的处理。
示例
创建Product.js处理product相关的api请求:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37// 存储Product列表,相当于模拟数据库:
let products = [{
name: 'iPhone',
price: 6999
}, {
name: 'Kindle',
price: 999
}];
module.exports = {
// localhost:3000/api/products
'GET /api/products': async (ctx, next) => {
// 设置Content-Type:
ctx.response.type = 'application/json';
// 设置Response Body:
// json object
// ctx.response.body = {
// products: products
// };
// json array
ctx.response.body = products;
},
// url:localhost:3000/api/products
// Content-Type:application/json
// params-style-body: {"name":"XBox","price":3999}
'POST /api/products': async (ctx, next) => {
let p = {
name: ctx.request.body.name,
price: ctx.request.body.price
};
products.push(p);
ctx.response.type = 'application/json';
ctx.response.body = p;
}
};
Nunjucks
Nunjucks官方文档自带中文版翻译;
模板引擎
Nunjucks是一个模板引擎,模板引擎就是基于模板配合数据构造出字符串输出的一个组件。
简介
Nunjucks是Mozilla开发的一个纯JavaScript编写的模板引擎,既可以用在Node环境下,又可以运行在浏览器端。但是,主要还是运行在Node环境下,因为浏览器端有更好的模板解决方案,例如MVVM框架。
安装
1 | $ npm install nunjucks --save |
API
Nunjucks支持在html模板中使用一些NunjucksAPI的逻辑语法;
block区块
模板可以通过block拆分成许多区块;
1 | {% block css %} |
模板继承
- 先定义一个基本的网页框架base.html:
1 | <html><body> |
- base.html定义了三个可编辑的块,分别命名为header、body和footer。子模板可以有选择地对块进行重新定义:
1 | {% extends 'base.html' %} |
koa2中使用
- 封装nunjucks,为koa异步函数的ctx添加render属性,用于渲染模板:
1 | /** |
- koa中,加载controller网络请求前加载模板引擎配置:
1 | const Koa = require('koa'); |
- http请求响应调用模板引擎渲染:
1 | module.exports = { |