前面章節已經介紹了源自於 Koa 的中間件和路由設計,前面介紹的靜態資源服務器和路由能夠經過 koa 的中間件輕鬆實現,後面章節要介紹的企業級 web 框架 egg.js 正是基於 koa 開發的,在本章的最後簡單介紹一下 koa 的使用前端
next generation web framework for node.jsnode
Koa 是一個使用 Node.js 的 web 開發框架,其核心是前面章節中反覆使用的洋蔥模型中間件,經過中間件解決 web 開發中的 http 處理、業務邏輯實現,web 框架須要具有兩個最基本的特徵git
有個說法講庫和框架的區別:You call library, framework calls you.github
koa 的 web 處理基礎功能經過中間件提供,其開發規範也是創建在洋蔥模型中間件基礎上,如今使用的是 koa 2.x 版本,在此以前 Node.js 社區 web 框架通過了幾個里程碑web
Express 是 Node.js 的第一代流行 web 開發框架,主要是對 http 模塊進行封裝,並提供了路由、模板渲染等 web 開發經常使用功能,功能齊全但須要全量引用express
因爲出現早於 Promise,錯誤處理使用 Node.js 的 callback 風格,相應有了回調地獄問題,不過隨着 Promise 流行,如今 Express 4.x、5.x 已經沒了這個問題npm
Express 中間件是線性執行的,每個中間件處理完成以後只有兩個選擇api
只要是離開中間件後就再也沒法返回,這樣的設計讓邏輯很是簡單,但在不少須要屢次處理請求的實現上變得複雜:好比統計一個請求的耗時,在 Express 中充斥着大量利用事件或者回調來 hack 這種需求的處理方式安全
exports.responseTime = function () {
return function (req, res, next) {
req.startTime = new Date(); // 開始時間
const trackTime = function () {
const endTime = new Date(); // 結束時間
const duration = endTime - req.startTime;
console.log('X-Response-Time: ', duration + 'ms');
}
res.once('finish', trackTime);
res.once('close', trackTime);
return next();
}
}
複製代碼
由於其簡單、功能高度集成的特性,Express 如今仍然是最流行的 Node.js web 開發框架,但功能高度集成帶來的不靈活和中間件的線性調用特性讓愈來愈多企業級 web 框架封裝都選擇了使用 koa服務器
Koa 一樣出自 Express 團隊之手,除了 API 變化,相對於 Express 作了兩個最重要的變動
異步的代碼書寫起來更像是同步代碼了,但使用 generator 中間件編寫風格如今看起來會感受怪怪的
app.use(function *(next) {
const startTime = new Date();
yield next;
const duration = new Date - startTime;
console.log('X-Response-Time: ', duration + 'ms');
})
複製代碼
理念和 Koa 1.x 一致,不過推薦異步處理變成了 async/await,其中間件實現也就是前面介紹過的 koa-compose,中間件編寫風格好理解了不少
app.use(async (ctx, next) => {
const start = Date.now();
await next();
const ms = Date.now() - start;
console.log(`${ctx.method} ${ctx.url} - ${ms}`);
});
複製代碼
koa 2.x 也把以前使用 this 獲取請求、響應等對象修改成了使用 ctx 對象
使用 koa 編寫 hello world 很是簡單
const Koa = require('koa');
const app = new Koa();
// response
app.use(ctx => {
ctx.body = 'Hello Koa';
});
app.listen(3000);
複製代碼
context 對象在每一個請求中被建立,是 koa 對當前請求的 request、response 對象封裝,並提供了不少實用處理工具方法,作爲中間件的第一個參數被傳入
app.use(async (ctx, next) => {
ctx; // is the Context
ctx.request; // is a koa Request
ctx.response; // is a koa Response
});
複製代碼
context 中用幾個經常使用的屬性
ctx.throw(400);
ctx.throw(400, 'name required');
ctx.throw(400, 'name required', { user: user });
複製代碼
koa 封裝的 request 和 response 對象包含了 Node.js 原生 req、res 的所有屬性,而且提供了不少快捷操做,再也不一一介紹
經過設置 response.body 能夠設置 http 響應,設置的值能夠是如下類型
string
Buffer
Stream
可讀流Object
|| Array
null
不返回響應使用 koa-static 中間件能夠輕鬆實現前面章節介紹的靜態資源服務器
const path = require('path');
const Koa = require('koa');
const static = require('koa-static');
const app = new Koa();
const root = path.join(__dirname, './public');
app.use(static(root, {}));
app.listen(3000);
複製代碼
官方介紹了三個學習 koa 的網站
其實只要瞭解了 Node.js 的 http 模塊和 koa 的洋蔥模型中間件,koa 很是好理解,但實現一個完整的 web 網站須要整合大量的中間件( koa 核心維護者死馬整理了一些經常使用的 www.npmjs.com/package/koa…)
var koa = require('koa');
var middlewares = require('koa-middlewares');
var router = middlewares.router();
var app = koa();
router.get('/', function *(){
this.body = 'hello koa-middlewares';
});
app.use(middlewares.bodyParser());
app.use(middlewares.conditional());
app.use(middlewares.etag());
app.use(middlewares.compress());
middlewares.csrf(app);
app.use(router.routes());
app.use(router.allowedMethods());
app.listen(7001);
複製代碼
看起來很是恐怖,這也是爲何會有不少基於 koa 的 web 開發框架,針對特定的功能整合了相應的中間件,併爲開發者處理了 web 安全、性能等相關問題,接下來介紹其中的佼佼者——企業級的 web 開發框架 egg.js