主要内容
- 了解 Koa 框架
- 学会 koa-genertor
- 了解 Node.js Web 框架的演进过程
1.1 Koa 简介
Koa 是 Node.js 的下一代 Web框架。
Koa 是由 Express 原班人马打造,是一个更小,更健壮,更富有表现力的 Web “微”框架。
进而实现使用 Koa 编写 Web 应用,通过组合各种更高级的异步流程控制中间件,来免除重复繁琐的回调函数嵌套,并极大提升常见错误的处理效率。
关于 Koa 的 V1 和 V2 差异
- 要明确的是 v1 和 v2 版本 API 方面基本无差异
- Koa v1 是基于 ES6 Generator 的。
- Koa v2 正式版本发布前,可通过 koa-convert 支持 3 种中间件写法,更现代,更时尚。
- Koa v2 正式版本发布后,主打 async 函数,要求使用 Node.js v7.6 以上版本。
- Koa v1 使用隐式的 this 作文上下文,而 Koa v2 则使用显式的 ctx 作为上下文,语义更清晰。
p.s Koa v2 版本在 2017 年 3 月发布
1.1.1 应用场景
以下列出了 Koa 的常用场景。
场景 | 描述 | 使用人员 |
---|---|---|
传统 Web 应用开发 | Koa 可以开发带有视图渲染和数据库操作的 Web 应用,主要以网站为主,前后端混在一起,开发简单,是入门和快速开发的利器 | 均可 |
作为服务端接口 | 使用 Koa 可以为 pc端,移动端,html5 端等提供 http API 支持 | 后端开发人员居多 |
作为独立 API 层 | 后端程序可能有多种语言实现,业务划分会导致跨域等各种情况出现,此时可以使用 Koa 作为 API 代理,来请求后端 API,处理后再将结果返回给前端 | 前端开发人员居多 |
RPC服务组装 | 由于历史问题,很多应用层采用 RPC 进行服务化,然后组装成 RPC 服务将其包装成最终 HTTP API提供调用。这是非常好的方式,这种场景是 Koa 非常擅长的组装 RPC 服务非常简单,不涉及数据库操作,可以按照前端要求的格式处理 | 均可 |
静态 API 模拟 | Koa 可以提供静态 API 接口,无须实现具体逻辑,能够加速开发 | 均可 |
API 网关 | 使用 Node.js 实现 HTTP 代理是非常简单的,使用 Koa 能够更好地请求转发 | 均可 |
与前端框架集成 | Koa为 Vue,React 等前端框架的集成提供开发部署环境的 HTTP 服务,静态 API 服务等,结合使用可以实现服务端渲染或同构开发。 | 前端开发人员居多 |
开发 Web 框架 | Koa 自身没用绑定任何中间件,使用 Koa 是往往要同时使用多个中间件,所以很多框架更愿意将 Koa 作为内核模块,在其之上进行定制开发。比如,知名框架 ThinkJS 在其 v 3.0 中采用 Koa 作为内核模块,抛弃了之前维护的 HTTP 基础库 | 均可 |
1.1.2 开发要点
Koa 自身比较简单,但是要想使用好,需要掌握以下开发要点。
- Koa 中间件
- ES6 语法:Koa 是基于 Node.js v4 以上版本进行开发的,所以对 ES6 语法支持的非常好。
- HTTP 基础
- 异步流控制:推荐顺序是, async函数 -> Promise -> Generator。
- 数据库操作:几乎所有的 Web 应用都涉及操作数据库,所以掌握数据库知识非常重要。数据库一般分为关系型数据库和飞关系型数据库。
- API 接口开发
1.1.3 Koa 入门
Koa v2 的核心是使用面向更新特性的 async 函数的中间件,其正式版本发布前后略有不同。
- 正式版本发布前:支持 3 种中间件的写法(Promise,Generator,async函数)。
- 正式版本发布后:推荐使用 ES2017 的 async 函数作为中间件。
下面将会是以代码为主导的示例。
- 初始化项目
这是使用 npm 初始化
// 初始化 Node.js 模块,创建 package.json 配置文件
npm init -y
// 安装 Koa 作为依赖模块
npm i -S koa@2
// 创建 app.js 作为应用入口
touch app.js // ( win 版本略有不同,可手动创建 )
接下来在 app.js 中写入以下服务代码:
const Koa = require('koa')
const app = new Koa()
// 日志中间件
app.use( async (ctx, next) => {
const start = new Date()
console.log('before await..')
await next()
console.log('after await...')
const ms = new Date - start
console.log(`${ctx.method} ${ctx.url} - ${ms} ms`)
} )
// 响应
app.use( async (ctx, next) => {
console.log('respones...')
ctx.body = 'Hello Koa 2'
} )
app.listen(3000)
下面是对 Koa 代码中的要点进行说明。
- 中间件使用了 async函数 + 箭头函数,这样的语义比 之前的 ES6 Generator 更加清晰。
- 参数增加了 ctx,比之前的 ES6 Generator 中间件只能使用隐式的 this 作为上下文更加友好。
在执行 app.js 之前,一定要确保你的 Node.js 是 v7.6 以上的,否则无法直接执行带有 async 函数的代码。
node app.js
tip: 为什么 Koa 中要新增一个 ctx 参数
新增 ctx 参数的最主要的原因是在箭头函数中,this 实在定义时绑定的,而不是在运行时绑定的。
Koa v1 和 Koa v2 的用法差异
Koa v1
const koa = require('koa')
const app = koa();
Koa v2
const Koa = require('koa')
const app = new Koa();
v1 和 v2 的差异主要来源于源码结构的变化
- v1 部分源码
var app = App.prototype;
module.exports = App;
function App() {
if (! (this instanceof App) ) {
return new App;
}
this.env = process.env.NODE_ENV || 'development';
this.subdomainOffset = 2;
this.middleware = [];
this.proxy = false;
this.context = Object.create(context);
this.request = Object.create(request);
this.create = Object.create(response);
}
- v2 部分源码
module.exports = class App extends Emitter {
constructor() {
super();
this.subdomainOffset = 2;
this.middleware = [];
this.proxy = false;
this.context = Object.create(context);
this.request = Object.create(request);
this.create = Object.create(response);
}
}
通过上面的源码对比,可以看出 v1 对外导出的函数,而 v2 对外导出的类,需要通过 new 这个关键子来实例化。另外,值得注意的是, v2 源码里,只有 App 进行了类化,其他仍然保持之前的风格。
1.1.4 为什么选择 Koa
为什么要在众多的框架中选择 Koa 呢,理由大概如下。
- 用 async 函数做异步流程控制时,代码更容易理解。
- 错误处理的干干净净。无论是 async 函数还是 Promise 规范都能很好地处理异常,另外 Koa 继承自 Event 的,结合 ctx 里的一些 API 能够更简单地处理错误。
- 具有优雅的回形针中间件机制。通过更少的代码可以完成更多的工作,尤其是能对响应部分做拦截。(可以跟 Express 作对比)
- 性能非常好。(跟 Express 作对比)
- Koa 核心代码量比较少,易于定制,易于在其上开发各种 Web框架。
- 社区生态逐渐完善。
- 国内外很多公司都已经大量应用 Koa 了,目前 Node.js 的首选 Web 架构是 Koa。
- 拥有 Egg.js (基于 Koa 的成熟的企业级 Web 开发框架),拥有庞大的插件生态。
- 拥有 MidwayJS。它基于 Egg.js 生态,使用 TS 编写,提供 IoC 容器,是面向未来的框架。
下面的部分讲继续介绍 Koa-generator 和 Node.js Web 框架的演进之路