Koa 學習筆記


開始

就像官網上說的,一切框架都從一個"Hello World"開始,首先我們新建一個 package.json,內容盡量簡單:

{
  "name": "koa-note",
  "description": "Koa 學習筆記",
  "main": "index.js"
}  

然后 npm 安裝 Koa

npm i koa

將官網上給的示例粘貼進去:

const Koa = require('koa');
const app = new Koa();

app.use(ctx => {
    ctx.body = 'Hello World';
});

app.listen(4000);

然后執行 node --harmony index.js,就可以在瀏覽器中訪問 http://localhost:4000/ 了。

注1:ctx 是 context 的簡寫,下面詳細介紹。

注2:示例源碼

2個關鍵點

Koa 的核心設計思路是為中間件層提供高級語法糖封裝,以增強其互用性和健壯性,並使得編寫中間件變得相當有趣。Koa 應用是一個包含一系列中間件 generator 函數的對象。

中間件級聯

Koa 通過 generators 來實現“真正”的中間件。 Connect 簡單地將控制權交給一系列函數來處理,直到函數返回。 與之不同,當執行到 yield next 語句時,Koa 暫停了該中間件,繼續執行下一個符合請求的中間件('downstrem'),然后控制權再逐級返回給上層中間件('upstream')。

    const Koa = require('koa');
    const app = new Koa();

    // 定制請求頭
    app.use(async function (ctx, next) {
        const start = new Date();
        await next();
        const ms = new Date() - start;
        ctx.set('X-Response-Time', `${ms}ms`);
    });

    // 日志
    app.use(async function (ctx, next) {
        const start = new Date();
        await next();
        const ms = new Date() - start;
        console.log(`${ctx.method} ${ctx.url} - ${ms}`);
    });

    // 請求內容
    app.use(ctx => {
        ctx.body = 'Hello World';
    });

上面的例子在頁面中返回 "Hello World",然而當請求開始時,請求先經過定制請求頭和日志中間件,並記錄中間件執行起始時間。 然后將控制權交給 reponse 中間件。當中間件運行到 yield next 時,函數掛起並將控制前交給下一個中間件。當沒有中間件執行 yield next 時,程序棧會逆序喚起被掛起的中間件來執行接下來的代碼。

為了方便理解我 YY 了下面的例子:

// 定制請求頭
app.use(async function (ctx, next) {
    console.log('step 1');
    await next();
    console.log('step 5');
});

// 日志輸出
app.use(async function (ctx, next) {
    console.log('step 2');
    await next();
    console.log('step 4:');
});

// 請求內容
app.use(ctx => {
    console.log('step 3');
});

注:示例源碼

說到中間件就不得不提到中間件的開發,簡單地說中間件就是一個回調函數,中間件的原理可以參考下面這個"洋蔥模型":

image"

2.x 版可以使用 yield 來分割 request 和 response,但是 2.0 發版后就明確說明在 3.x 希望使用 await 來代替 yield,也就是要從 generator function 升級到 async function。某些組件還沒有進行升級,經常會看到控制台上又這樣的警告信息 "Support for generators will be removed in v3.",其中常用的 koa-router 和 koa-proxy 就在其中,如果想去除警告,並且與下一個版本兼容,可以參考 koa-static 這個庫(做靜態文件路由的一個中間件)。

app 的幾個方法

app.listen(),為應用綁定端口,參數的詳細文檔請查看nodejs.org

app.callback(),返回一個適合 http.createServer() 方法的回調函數用來處理請求。

app.use(function),為應用添加指定的中間件,詳情請看 Middleware

app.keys=,設置簽名Cookie密鑰。

app.context,方便擴展 ctx:

app.context.db = db();

app.use(async (ctx) => {
  console.log(ctx.db);
});

app.on,典型的是錯誤處理:

app.on('error', function(err){
  log.error('server error', err);
});

上下文

Koa Context 將 node 的 request 和 response 對象封裝在一個單獨的對象里面,其為編寫 web 應用和 API 提供了很多有用的方法。

app.use(function *(){
  this; // is the Context
  this.request; // is a koa Request
  this.response; // is a koa Response
});

一堆 API 就不寫了,自行到官網查看。

中間件

Koa 就是一個框架,大部分功能還需要靠中間件實現。

中間件 koa-router

安裝

npm install koa-router

使用

const Koa = require('koa');
const app = new Koa();
const router = require('koa-router')();

router.get('/', function *(next) {
    this.body = 'Hello World!';
});

router.get('/a', function *(next) {
    this.body = 'Hello World A!';
});

app.use(router.routes());
app.listen(4000);

console.log('服務已啟動: localhost:4000');

RESTFul 風格的路由像這樣配置:

router.get('/users/:id', function *(next) {
    // ...
}).del('/users/:id', function *(next) {
    // ...
});

官網:koa-router

中間件 koa-static

安裝

npm i koa-static --save

使用

const koaStatic = require('koa-static')('./');
app.use(koaStatic);

說明:

  • 第一個參數指定根路徑
  • 第二個參數指定各種配置項

注意:

默認請求指向 index.html 文件,當然你可以通過第二個參數 options 自定義默認請求的文件。如果配置了 koa-router 的默認路徑那么靜態文件的路由默認會失效。如下面訪問 http://localhost:4000/ 這樣的路徑會返回報 404,而不會去讀取 ../dist/index.html 文件並返回。

router.get('/', function *(next) {
});
const koaStatic = require('koa-static')('./', {
    index: '../dist/index.html'
});

其他參數參考 koa-static 中間件官網:koa-static

注:示例源碼,示例驗證了 HTML,圖片,CSS 和 JS 靜態文件的加載。

中間件 koa-proxy

安裝

npm i koa-proxy --save

代理接口,默認只代理接口不代理靜態文件,當前的 router 優先,也就是說如果已經配置了某接口的路由,那么此接口不會被代理帶其他服務器上。

const koaProxy = require('koa-proxy')({
    host: 'http://127.0.0.1:5000'
});
app.use(koaProxy);

也可以給靜態文件做遠程代理:

app.get('index.js', proxy({
  url: 'http://127.0.0.1:5000/index.js'
}));

注1:示例源碼。 注2:中間件 koa-proxy

意外收獲的包

讀源碼的時候發現了很多服務器開發有用的包,下面列一下:

co

Generator 函數執行器,TJ大神的作品。GitHub

co(gen);

methods

Node 支持的 http 類型,這種只返回一個數組的小包居然也是 TJ 大神創立的。GitHub

assert

對 Node 原生包的擴展,支持瀏覽器。GitHub

// 判空
assert(root, 'root directory is required to serve files');

http-errors

處理 http 異常的模塊,這個做服務器端開發肯定少不了。GitHub

cookie

這種包用途也很廣泛。GitHub

path-to-regexp

非常棒的路徑匹配和 RESTFul 地址轉化的工具。GitHub

is-generator-function

判斷一個函數是否是 Generator 函數。GitHub

const isG = require('is-generator-function');
isG(fn);

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM