2016年6月6日 星期一

下一代的框架:Koa 1.0 起手式

Standard


身為 Node.js 使用者的你,還在使用 Express 嗎?快來使用下一代的 Web Framework 吧!Koa 是由 Express 的開發者們出來所開發的新網站框架,嘗試採用了最新的 ECMAScript 6 語法,讓開發者可以用更簡約的方式,開發網站應用程式,讓程式碼更好維護之外,也能受益於最新的語言特性。

穩定版與不穩定版


現在的 Koa 分為 1.0 和 2.0 兩個版本,1.0 使用 ES6 的 Generator 特性,也是目前的 stable 版本,而 2.0 採用 ES7+ 的 async/await,據 Koa 官方說法,2.0 穩定度可以用於實際產品,只是在 ECMAScript 7 規格正式敲定,且 JavaScript V8 Engine 推出原生的實作之前,將無限期處於 unstable 的狀態。也就是說,若你想要在你自己的專案上使用 2.0,你必須使用 babel 這一類的編譯器,因為裡面用到了 ES7 的語法。

本篇文章的重點將放在 Koa 1.0 之上,畢竟在 ECMAScript 7 還處於草案階段的現在,很難說未來會不會有什麼改變。

安裝 Koa


由於 Koa 需要用到 ECMAScript 6 的語言特性,請先檢查你的 Node.js 版本,最少為 0.12 以上,如果你已經使用了 Node.js 4.0 或更高版本,請不用擔心這個問題。

然後透過 NPM 即可安裝模組:
npm install koa

開發第一個應用程式


開發 Koa 應用程式非常容易,下面是程式碼範例:
var koa = require('koa');

var app = koa();

app.use(function *() {
    this.body = 'Hello World';
});

app.listen(3001);
跑起來後,用瀏覽器連入 3001 埠即可看到「Hello World」的字樣,因為 this.body 的內容,將會被輸出到前端瀏覽器上。

使用 Generator 打造的 Middleware


koa.use() 將用來載入 Middleware,所有連線工作都會經過 Middleware 處理。所以前一個例子裡,我們使用 koa.use() 設定了一個處理函數,該函數會用來處理所有連線工作。

要注意的是,在 function 後面有一個「*」的符號,這代表這個函數是一個 Generator 函數,所以這函數裡面的程式將可以使用 Generator 的語言特性。若您不知道 Generator 是什麼,可以參考過去的舊文「快樂玩 ES6 Generator,從 co 起手式開始」。

【註一】如果你有過 express 開發經驗,對於 koa.use() 會相當熟悉,Koa 同樣支援了 Middleware 的架構,你可以將過去的程式輕易移植到這新的框架上。
【註二】Koa 底層使用 co 來操作 Generator,若你覺得 Generator 太過艱澀,只需要了解 co 的使用即可。

加入多個 Middleware


所有的連線要求可以透過一系列、不只一個 Middleware 來處理,我們可以利用多次 koa.use() 來使用它,範例如下:
var koa = require('koa');

var app = koa();

app.use(function *(next) {
    yield next;
});

app.use(function *() {
    this.body = 'Hello World';
});

app.listen(3001);

一個 Middleware 可以透過 yield 傳入 next 參數,讓連線要求進入到下一個 Middleware 被處理。

自訂 Router 和路徑管理


之前的範例直接使用 koa.use(),會將所有的連線都導入同一個處理函數,輸出同一個結果。若我們想要自訂不同的路徑,讓不同路徑用不同的處理函數,將需要額外安裝「koa-router」模組:
npm install koa-router

然後可以直接修改我們的程式碼如下:
var koa = require('koa');
var Router = require('koa-router');

var app = koa();
var router = new Router();

// 針對不同路徑套用不同處理函數
router.get('/', function *() {
    this.body = 'HOME';
});

router.get('/myapi', function *() {
    this.body = 'API';
});

// 載入自訂的 router
app.use(router.middleware());
app.listen(3001);
範例中只有使用到「GET」方法,如果要用來開發 Restful API 或是處理一些表單上傳的工作,可以依樣畫葫蘆使用 router.post、router.put 或 router.del 方法。

接收 QueryString 的資料


QueryString 可說是歷史悠久且非常常見的傳值方法,藉由一個網址後面加上一個「?」字元後,就可以使用鍵值(Key/Value)來進行資料傳遞,並用「&」區隔多組資料。一個簡單的實際應用如下:
http://my_server/send?name=fred&msg=Hello

取得資料的方法如下:
console.log(this.request.query.name);
console.log(this.request.query.msg);

接收 body 的資料


當我們使用「POST」或「PUT」方法,我們就可以利用 body 傳送一些資料到伺服器,像是網頁表單時常使用這樣的傳值方法。若想要取得 body 的資料,必須先安裝一個「koa-bodyparser」模組:
npm install koa-bodyparser

使用 koa.use() 載入 koa-bodyparser,koa 就會自動在處理連線時使用它解析 body:
var bodyParser = require('koa-bodyparser');

app.use(bodyParser());

然後可以在路徑處理函數中,正常取得 body 內的資訊:
console.log(this.request.body.name);
console.log(this.request.body.msg);

靜態文件支援


除了一般動態網頁外,我們也會在網頁中嵌入 CSS、前端的 JavaScript 和圖片等靜態檔案,這些檔案在瀏覽器載入頁面時,同時間也要提供瀏覽器能取得。為了達成這功能,可以使用「koa-static」來達成:
npm install koa-static

然後可以直接加入這個 middleware:
var serve = require('koa-static');

app.use(serve(__dirname + '/public'));

其中要帶入路徑參數,告訴 koa-static 去哪個目錄尋找對應的靜態檔案,範例中是設定為此程式同一個目錄下的 public 目錄。

Session 支援


要使用 Session 要先安裝 koa-session:
npm install koa-session

然後就可以在處理函數中使用 this.session 這個物件來存放資料:

var koa = require('koa');
var Router = require('koa-router');
var session = require('koa-session');

var app = koa();
var router = new Router();

// 設定一組金鑰,用來加密 session
app.keys = [ '$*&!@#$^)*(DSIJCH(*&@#' ];

// 載入 session middleware
app.use(session(app));

// 每次連線就將計數器加一
app.use(function *(next) {
    if (this.session.counter)
        this.session.counter = 0;

    this.session.counter++;

    yield next;
});

router.get('/', function *() {
    // 回傳顯示計數器的值
    this.body = this.session.counter;
});

// 載入自訂的 router
app.use(router.middleware());
app.listen(3001);

這範例會在瀏覽器每次連線時,把 session 內的計數器加一,所以若是我們重複整理這個頁面,會看到數字不斷增長。

要注意的是,使用 session 前,我們要為 app.keys 設一組金鑰(Key), koa-session 會使用這組 Key 加密我們的 session 資料。

後記


還在使用 express 嗎?別老土了。(笑)