解讀並實現乙個簡單的koa router

2021-09-11 14:23:35 字數 3354 閱讀 2398

koa 應用程式是乙個包含一組中介軟體函式的物件,它是按照類似堆疊的方式組織和執行的。

這是 koa 對自己的介紹,其他 koa 依賴的庫其實都可以算是中介軟體,koa-router 也不例外。

ps: 本文**中的中文解釋是對**的講解,省略號(...)代表省略部分**

對 koa-router 的猜想

通過 koa 最簡單的 hellow world 例子可以看出原生對請求的處理方式:

const koa = require('koa');

ctx.body = 'hello world';

});複製**

要是我們想簡單的實現路由的話,可以新增一些判斷條件

if (ctx.path === '/one' && ctx.method === 'get') else

});複製**

這樣的話能實現簡單對路由的實現,不過路由越多的話消耗的效能也就越大,而且不容易對特殊路由新增中介軟體。而更好的方法是使用物件導向的方式,根據請求的 path 和 method 返回相應的中介軟體處理函式和執行函式。

解讀思路

router 執行流程圖

我認為 koa-router 最基本且核心的api有四個:

router.match 可以根據請求的 path 和 method 篩選出匹配的 route

router.register 註冊 route

router.routes 返回用於 koa 載入的中介軟體,通過 koa-compose 將middlewares 壓縮成乙個函式

router.method(get、post等) 可以根據path、method 定義 router,並且可以將middleware繫結在路由上

解讀我們可以結合**和單元測試對原始碼進行理解,由最簡單的測試開始debug:

it('router can be accecced with ctx', function (done) ;

});console.log(router.routes()); // 這是我加的,檢視最後載入的routes

.get('/')

.expect(200)

.end(function (err, res) );

});複製**

router.routes() 返回:

function dispatch(ctx, next) , );

return compose(layerchain)(ctx, next);

}複製**

router.routes()返回乙個 dispatch 函式,從中可以看出請求進來會經過router.match(後面有分析),然後將匹配到的 route 的執行函式 push 進陣列,並通過 compose(koa-compose) 函式合併返回。

然後在列印出 compose(layerchain) 方法,可以看到其實最後請求執行的函式是對ctx.body = ;的 compose 封裝函式,在效果上相當於

ctx.body = ;

});複製**

function router(opts) 

this.opts = opts || {};

// 定義各方法

this.methods = this.opts.methods || [

'head',

'options',

'get',

'put',

'patch',

'post',

'delete'

];this.params = {};

// 初始化定義 route 棧

this.stack = ;

};複製**

// methods ['get', 'post', 'delete', 'put', 'patch', ...]

methods.foreach(function (method) else

// 註冊 route(下面會講到 register 方法)

this.register(path, [method], middleware, );

// 返回 router 物件,可以鏈式呼叫

return this;

};});複製**

router.prototype.register = function (path, methods, middleware, opts) ;

var stack = this.stack;

...// create route

// 例項化乙個 layer 物件,layer 物件將 path 轉為 regexp,並增加了匹配 path 的可選 ops 引數

var route = new layer(path, methods, middleware, );

console.log(route);

/*** layer } // 用於匹配 path

*/...

// 將註冊的 route 存放在 stack 佇列中

stack.push(route);

return route;

};複製**

register 方法主要用於例項化 layer 物件,並支援多各 path 同時註冊、新增路由字首等功能(展示**忽略)。

router.prototype.match = function (path, method) ;

// 迴圈查詢能夠匹配的route

for (var len = layers.length, i = 0; i < len; i++)

}} return matched;

};複製**

實現簡版router

通過上面的分析,其實已經講解了 koa-router 核心的部分:構造 router 物件 => 定義 router 入口 => 匹配路由 => 合併中介軟體和執行函式輸出;這4個api可以處理簡單的 restful 請求,額外的api例如重定向、router.use、路由字首等在了解核心**後閱讀起來就簡單很多了;簡版其實就是上面api的精簡版,原理一致,可以到我的專案看下

總結koa-router 幫我們定義並選擇相應的路由,對路由新增中介軟體和一些相容和驗證的工作;在 koa 中介軟體應用的基礎上,比較容易理解中介軟體的實現,koa-router 為我們做了更好的路由層管理,在設計上可以參考實現,同時研究優美原始碼也是對自己的一種提公升。

乙個簡單的Matrix實現

我們直接來看 吧 matrix.h pragma once include using namespace std 矩陣類 class matrix 下面是實現和測試的 matrix.cpp include matrix.h include include matrix matrix void ma...

LinkList的乙個簡單實現

鏈式線性表是資料結構裡很簡單但也是很常見的資料結構,相比順序儲存的線性表,可以更快的實現新增和刪除操作,但讀取速度比順序結構會慢。鏈式線性表的關鍵在於,每個資料儲存為節點形式。不僅僅儲存有資料,還有乙個引用 next 指向下乙個節點。鏈式結構還可以再擴充套件為雙向鍊錶 迴圈鍊錶等等。基本原理一樣,只...

實現乙個簡單的 shared ptr

智慧型指標的作用有如同指標,但會記錄有多少個 shared ptrs 共同指向乙個物件。這便是所謂的引用計數。一旦最後乙個這樣的指標被銷毀,也就是一旦某個物件的引用計數變為 0,這個物件會被自動刪除。shared ptr 的實現機制其實就是在拷貝構造時使用同乙份引用計數。同乙個 shared ptr...