Koa中常用的中介軟體:
- koa-session:讓無狀態的http擁有狀態,基於cookie實現的後臺儲存資訊的session
- koa-mysql:封裝了需要用到的SQL語句
- koa-mysql-session:當不想讓session儲存到記憶體,而想讓session儲存到mysql資料庫中時使用
- koa-router:後臺會接受到各種請求的url,路由會根據不同的url來使用不同的處理邏輯。
- koa-view:請求html頁面時,後臺會用模板引擎渲染資料到模板上,然後返回給後臺
- koa-static:請求img、js、css等檔案時,不需要其他邏輯,只需要讀取檔案
- koa-better-body:post上傳檔案時,解析請求體
koa系列文章:
- koa框架會用也會寫—(koa的實現)
- koa框架會用也會寫—(koa-router)
- koa框架會用也會寫—(koa-view、koa-static)
- koa框架會用也會寫—(koa-bodyparser、koa-better-body)
koa-router的使用
var Koa = require('koa');
var Router = require('koa-router');
var app = new Koa();
var router = new Router();
router.get('/home',(ctx,next)=>{
ctx.body = 'home'
next();
});
router.get('/user', (ctx, next) => {
ctx.body = 'user';
next();
});
app.use(router.routes()).use(router.allowedMethods());
複製程式碼
koa-router的奧祕
假如沒有koa-router
var Koa = require('koa');
var Router = require('koa-router');
var app = new Koa();
var router = new Router();
//將路由的處理交給中介軟體
app.use((ctx, next) => {
if (ctx.path === '/' && ctx.method === 'GET') {
ctx.body = '首頁'
} else {
next();
}
})
app.use((ctx, next) => {
if (ctx.path === '/user' && ctx.method === 'GET') {
ctx.body = '使用者'
} else {
next();
}
});
複製程式碼
從上面可以知道,如果沒有koa-router,其實每個路由使用的koa註冊中介軟體的形式來進行處理的,這樣不利於鬆耦合和模組化,所以將所有路由的處理邏輯抽離出來組合成一個大的中介軟體koa-router來處理,最後將大的中介軟體註冊到koa上,如果關於koa中介軟體原理還不瞭解,可以參考另一篇文章koa框架會用也會寫—(koa的實現)
koa-router的原理
既然koa-router也是大的中介軟體,裡面擁有許多小的中介軟體,那麼裡面必然也需要用到洋蔥模型,洋蔥模型的特點:
- middles:存放中介軟體的容器,用來存放註冊的中介軟體
- get(path,fn):用來註冊中介軟體,往middles中存放,由於是路由中介軟體這裡多了一個引數path
- compose():用來組合中介軟體,讓路由中介軟體按順序執行
- routes():用來將koa-router中介軟體註冊到app的中介軟體上,主要作用是呼叫路由中介軟體匹配請求的路徑ctx.path
如果對於中介軟體和洋蔥模型有疑問的,可以參考koa框架會用也會寫—(koa的實現)
middles:存放中介軟體的容器,用來存放註冊的中介軟體
class Router {
constructor(){
this.middles=[];
}
}
module.exports = Router
複製程式碼
get(path,fn):用來註冊中介軟體,往middles中存放,由於是路由中介軟體這裡多了一個引數path
class Router {
constructor(){
this.middles=[];
}
get(path,fn){//set,post等同理
let layer = {
path,
fn,
method
}
//處理類似/article/:id的路由
if(path.includes(':')){
let params = [];
let reg = path.replace(/:([^\/]*)/g,function () {
params.push(arguments[1]); //params = [id]
return '([^\/]*)' //返會字串/article/([^\/]*)
});
//將返回的字串變成正則,後面解析路由是會用到
layer.reg = new RegExp(reg);//返回/\/article\/([^\/]*)/
layer.params = params;
}
this.middles.push(layer);
}
}
module.exports = Router
複製程式碼
compose():用來組合中介軟體,讓路由中介軟體按順序執行
class Router {
constructor(){
this.middles=[];
}
get(path,fn){//set,post等同理
let layer = {
path,
fn,
method
}
//處理類似/article/:id的路由
if(path.includes(':')){
let params = [];
let reg = path.replace(/:([^\/]*)/g,function () {
params.push(arguments[1]); //params = [id]
return '([^\/]*)' //返會字串/article/([^\/]*)
});
//將返回的字串變成正則,後面解析路由是會用到
layer.reg = new RegExp(reg);//返回/\/article\/([^\/]*)/
layer.params = params;
}
this.middles.push(layer);
}
compose(lasts,next,ctx){//lasts為匹配的路由集合
dispatch(index){
if(index === lasts.length) return next();
let route = lasts[index];
//將路徑引數都取出來exp:id的值
let params = route.params;
let [, ...args] = pathname.match(route.reg);
ctx.request.params = params.reduce((memo,key,index)=>(memo[key] = args[index], memo), {});
//執行路由邏輯,next賦值為下一個路由邏輯
route.fn(ctx,()=>{
dispatch(index+1);
})
}
dispatch(0)
}
}
module.exports = Router
複製程式碼
routes():用來將koa-router中介軟體註冊到app的中介軟體上,主要作用是呼叫路由中介軟體匹配請求的路徑ctx.path
class Router {
constructor(){
this.middles=[];
}
get(path,fn){//set,post等同理
let layer = {
path,
fn,
method
}
//處理類似/article/:id的路由
if(path.includes(':')){
let params = [];
let reg = path.replace(/:([^\/]*)/g,function () {
params.push(arguments[1]); //params = [id]
return '([^\/]*)' //返會字串/article/([^\/]*)
});
//將返回的字串變成正則,後面解析路由是會用到
layer.reg = new RegExp(reg);//返回/\/article\/([^\/]*)/
layer.params = params;
}
this.middles.push(layer);
}
compose(lasts,next,ctx){//lasts為匹配的路由集合
dispatch(index){
if(index === lasts.length) return next();
let route = lasts[index];
route.fn(ctx,()=>{
dispatch(index+1);
})
}
dispatch(0)
}
routes() {
// ctx上下文next指的是koa中的next方法
return async (ctx, next) => {
let pathname = ctx.path; //請求的路徑
let lasts = this.middles.filter(item => {
if (route.reg) { // 說明當前路由是一個路徑引數
if (method === route.method && route.reg.test(pathname)) {
return true //路徑引數匹配到了,新增進路由組
}
}
if ((method === route.method || route.method === 'all') && (route.p === pathname || route.p === '*')) {
return true //路徑是'/'或者'all',新增進路由組
}
return false;
});
this.compose(lasts, next, ctx);
}
}
}
module.exports = Router
複製程式碼
關於其他
上面的router是簡化版的koa-router,它只實現了koa-router中的一級路由,但是卻是能說明koa-router的主要思想,koa-router中新增了use來註冊二級路由,同時新增了很多包括重定向等其他邏輯處理
結語
koa-router中介軟體的原理基本就介紹完了,後面一起學習kao的其他中介軟體: