koa-router源碼地址是 koa-router
當前解讀版本爲7.2.1javascript
代碼結構圖
執行流程圖
關係對應圖
html
註冊註冊路由的方法,結果就是Router的原型上面多了get,post,delete,del等註冊路由的方法
代碼使用的時候 r1.get就是這麼來的java
r1.get('/test1/:id', function (ctx, next) { console.log('test1 :1') next() }, function (ctx, next) { console.log('test1:2') })
等同於 Router.prototype.deletenode
註冊中間件,支持形式多種多樣
看着這麼多,其實就兩種中間件,git
重點就是router.routes()返回的這種件,須要的前綴,參數驗中間件作一些處理github
router.use(function (ctx, next) { ctx.foo = 'baz'; return next(); }); router.use('/foo/bar', function (ctx, next) { ctx.foo = 'foo'; return next(); }); router.use('/foo', subrouter.routes()); router.use(['/foo', '/bar'], function (ctx, next) { ctx.foo = 'foo'; ctx.bar = 'bar'; return next(); }); parentRouter.use('/parent-route', function (ctx, next) { ctx.n = ctx.n ? (ctx.n + 1) : 1; return next(); }, nestedRouter.routes());
給router實例添加前綴,前綴能夠是包含參數的segmentfault
router.prefix('/things/:thing_id')
返回中間件,
中間執行的時候,會根據path獲取知足匹配條件的路由(Layer),而後根據每一個Layer生成一個解析參數值的中間,這就是爲何咱們在ctx.params能獲得參數值
最核心的代碼以下數組
layerChain = matchedLayers.reduce(function(memo, layer) { memo.push(function(ctx, next) { ctx.captures = layer.captures(path, ctx.captures); ctx.params = layer.params(path, ctx.captures, ctx.params); return next(); }); return memo.concat(layer.stack); }, []); return compose(layerChain)(ctx, next);
matchedLayers是匹配的Layer或者說一條路由信息,同一個路徑一樣的方法也是會生成兩條記錄的,以下一樣的註冊,會生成兩個不一樣路由(Layer),哪怕信息如出一轍app
r1.get('/test1', function (ctx, next) { console.log('test1 :1') next() }) r1.get('/test1', function (ctx, next) { console.log('test1 :2') next() })
matchedLayers.reduce沒執行一次,是生成兩個中間件,
一個是參數解析的中間件,這就是爲何你能夠經過ctx.params取值到路由參數了koa
function(ctx, next) { ctx.captures = layer.captures(path, ctx.captures); ctx.params = layer.params(path, ctx.captures, ctx.params); return next(); }
另一個纔是實際路由匹配的執行方法,上面的demo就是
function (ctx, next) { console.log('test1 :1') next() }
此方法執行很靠後,在他後面註冊的中間件執行完畢後才執行
生成一箇中間件,做用是定義路由沒匹配到,方法未容許,方法未實現等的返回信息
app.use(router.routes()); app.use(router.allowedMethods({ throw: true, notImplemented: () => new Boom.notImplemented(), methodNotAllowed: () => new Boom.methodNotAllowed() }));
註冊一個路由,容許全部的get,post等方法訪問
跳轉,原理就是註冊了一個路由,用ctx.redirect來實現跳轉
router.redirect('/login', 'sign-in');
等同於
router.all('/login', function (ctx) { ctx.redirect('/sign-in'); ctx.status = 301; });
核心方法之一,註冊中間件
Router.prototype.all,methods.forEach等底層都是調用這個傢伙實現的
Router.prototype.use也依據狀況會調用
查找具名的route(Layer)
生成url,能夠傳參
router.get('user', '/users/:id', function (ctx, next) { // ... }); router.url('user', 3); // => "/users/3" router.url('user', { id: 3 }); // => "/users/3" router.use(function (ctx, next) { // redirect to named route ctx.redirect(ctx.router.url('sign-in')); })
得到匹配的路由(Layer),以path和method來過濾的
router.routes返回的中間件底層就是經過他來確認請求應該進入哪些路由的
添加參數驗證中間件,這個須要結合Layer.prototype.param 一塊兒來理解
Router.prototype.param = function (param, middleware) { this.params[param] = middleware; this.stack.forEach(function (route) { route.param(param, middleware); }); return this; }; Layer.prototype.param = function (param, fn) { var stack = this.stack; var params = this.paramNames; // 構建參數驗證中間件 var middleware = function (ctx, next) { return fn.call(this, ctx.params[param], ctx, next); }; middleware.param = param; var names = params.map(function (p) { return p.name; }); var x = names.indexOf(param); if (x > -1) { // iterate through the stack, to figure out where to place the handler fn stack.some(function (fn, i) { // param handlers are always first, so when we find an fn w/o a param property, stop here // if the param handler at this part of the stack comes after the one we are adding, stop here // fn.param 做爲判斷是否是參數驗證中間件的標誌 // 若是不是參數驗證中間件,或者參數驗證中間件須要驗證的參數在我以後,插入參數驗證中間件 // 好比說path是這樣的 /user/:id/posts/:postid, 那麼id參數驗證中間件應該在postid參數以前 // 簡單說,確保參數按照順序被驗證 if (!fn.param || names.indexOf(fn.param) > x) { // inject this param handler right before the current item stack.splice(i, 0, middleware); return true; // then break the loop } }); } return this; };
path是否匹配路由
得到路由參數鍵值對
得到路由參數的值
用參數構建URL,params參數可視是對象也但是數組
添加參數驗證中間件
設置前綴
decodeURIComponent錯誤時返回原值
更多細節請直接看帶備註的源碼吧,寫東西真累啊!
Router
Layer
koa-router 源碼解析 - segmentfault
解析Koa-Router,邁入Web次時代第一步(上)
Koa-Router 源碼解析下 -CNode
koa-router源碼解讀