之前的文章我們介紹了一下 koa 路由,get 傳值,動態路由,本節我們看一下 koa 中介軟體 以及 koa 中介軟體的洋蔥圖執行流程。
一、什麼是 Koa 的中介軟體
通俗的講:中介軟體就是匹配路由之前或者匹配路由完成做的一系列的操作,我們就可以把它叫做中介軟體。
在express中介軟體(Middleware)是一個函式,它可以訪問請求物件(request object (req)), 響應物件(response object (res)), 和 web 應用中處理請求-響應迴圈流程中的中介軟體,一般被命名為 next 的變數。在 Koa 中中介軟體和 express 有點類似。
中介軟體的功能包括:
執行任何程式碼。
修改請求和響應物件。
終結請求-響應迴圈。
呼叫堆疊中的下一個中介軟體。
如果我的 get、post 回撥函式中,沒有 next 引數,那麼就匹配上第一個路由,就不會往下匹 配了。如果想往下匹配的話,那麼需要寫 next()
二、Koa 應用可使用如下幾種中介軟體:
應用級中介軟體
路由級中介軟體
錯誤處理中間件
第三方中介軟體
我們先來看一下應用級中介軟體,我們還是按照之前的專案將 app.js 改為如下:
1 //引入 koa模組 2 var Koa = require('koa'); 3 var Router = require('koa-router'); 4 5 //例項化 6 var app = new Koa(); 7 var router = new Router(); 8 9 //匹配任何路由,如果不寫next,這個路由被匹配到了就不會繼續向下匹配 10 app.use(async (ctx, next) => { 11 console.log("我是一箇中介軟體"); 12 // 當前路由匹配完成以後繼續向下匹配 13 await next(); 14 }); 15 16 //配置路由 17 router.get('/', async (ctx) => { 18 ctx.body = "首頁"; 19 }); 20 router.get('/news', async (ctx) => { 21 ctx.body = "新聞列頁面"; 22 }); 23 24 //啟動路由 25 app.use(router.routes()); 26 app.use(router.allowedMethods()); 27 28 app.listen(3000);
我們在匹配路由之前寫了一個 app.use(async ()=>{}) 的中介軟體,該中介軟體如果不像 router.get 那樣寫一個引數 "/" 或 "/news",那麼它將匹配任何一個路由,且最先匹配,如果我們在其中寫 next() 的話,則會終止在此,不再向下陪陪路由,執行結果如下:
我們在編輯器的控制檯看一下輸出日誌:
接下來我們看一下路由中介軟體:
1 //引入 koa模組 2 var Koa = require('koa'); 3 var Router = require('koa-router'); 4 5 //例項化 6 var app = new Koa(); 7 var router = new Router(); 8 9 //配置路由 10 router.get('/', async (ctx, next) => { 11 console.log("控制檯列印"); 12 // 當前路由匹配完成以後繼續向下匹配 13 await next(); 14 }); 15 router.get('/', async (ctx) => { 16 ctx.body = "首頁"; 17 }); 18 router.get('/news', async (ctx) => { 19 ctx.body = "新聞列頁面"; 20 }); 21 22 //啟動路由 23 app.use(router.routes()); 24 app.use(router.allowedMethods()); 25 26 app.listen(3000);
在上面的程式碼中我們定義了兩個 router.get('/', ) 的路由,第一個我們在控制檯輸出一句話,第二個我們想頁面輸出內容。如果在第一個裡面我們不寫 next() 方法的話,則不會進入第二個裡面,結果如下:
控制檯列印結果
接下來我們看一下錯誤處理中介軟體:
1 //引入 koa模組 2 var Koa = require('koa'); 3 var Router = require('koa-router'); 4 5 //例項化 6 var app = new Koa(); 7 var router = new Router(); 8 9 //匹配任何路由,如果不寫next,這個路由被匹配到了就不會繼續向下匹配 10 app.use(async (ctx,next)=>{ 11 await next(); 12 //如果頁面找不到 13 if(ctx.status==404){ 14 ctx.status = 404; 15 ctx.body="404 頁面" 16 } 17 }); 18 19 //配置路由 20 router.get('/', async (ctx) => { 21 ctx.body = "首頁"; 22 }); 23 router.get('/news', async (ctx) => { 24 ctx.body = "新聞列頁面"; 25 }); 26 27 //啟動路由 28 app.use(router.routes()); 29 app.use(router.allowedMethods()); 30 31 app.listen(3000);
我們還按之前的應用中介軟體那樣寫,然後在裡面做了一個 if 語句判斷,當頁面響應時,會給後端返回一個 status 碼,這個就不在單獨說了,如果這個 status 報 404,我們知道表示該頁面不存在,那麼我們就可以攔截 next() 方法,輸出給前端一個 404 頁面,結果如下:
我們匹配了一個 "/news" 路由,可以正常顯示內容,如果我們不小心少寫一個 "s",寫成了 "new",結果如下:
在上面的程式碼中我們是將 if 判斷語句放在了 next() 方法之後,那能不能放在 next() 之前呢?這個問題我們在下面的 koa 中介軟體流程控制中再詳細說明。
第三方中介軟體在之後的文章中我們用到了第三方模組時再說。
接下來我麼看一下 koa 中的中介軟體流程控制。
koa被認為是第二代node web framework,它最大的特點就是獨特的中介軟體流程控制,是一個典型的洋蔥模型。
上面的兩張圖可以很直觀的說明 koa 中的中介軟體流程控制。我們接下來用程式碼演示一下:
1 //引入 koa模組 2 var Koa = require('koa'); 3 var Router = require('koa-router'); 4 5 //例項化 6 var app = new Koa(); 7 var router = new Router(); 8 9 app.use(async (ctx, next) => { 10 console.log('1、這是第一個中介軟體01'); 11 await next(); 12 console.log('5、匹配路由完成以後又會返回來執行中介軟體'); 13 }); 14 15 app.use(async (ctx, next) => { 16 console.log('2、這是第二個中介軟體02'); 17 await next(); 18 console.log('4、匹配路由完成以後又會返回來執行中介軟體'); 19 }); 20 21 router.get('/', async (ctx) => { 22 console.log('3、匹配到了news這個路由'); 23 ctx.body = "首頁"; 24 }); 25 26 //啟動路由 27 app.use(router.routes()); 28 app.use(router.allowedMethods()); 29 30 app.listen(3000);
我們在上面的程式碼引用了兩個應用級的中介軟體,分別在 next() 前後輸出日誌,當我們訪問 localhost:3000/ 時,我們看一下控制檯的輸出結果:
從輸出列印結果順序我們可以看出中介軟體會先逐級處理 request 請求,然後再返回來逐級處理 response 請求,這就是我們為什麼要將 錯誤處理中介軟體 中的 if 判斷語句放在 next() 方法之後,這樣就是在路由進入 "/news" 後返回 status = 404 的結果後再進行處理,如果放在了 next() 方法之前,則會直接判斷 if 語句,不會再向下匹配 "/news" 路由了。比如我們的使用者登入系統就可以這麼用,當使用者輸入賬號密碼後出入後臺,後臺在資料庫匹配之後再進行處理,處理之後返回給前端,就是這麼玩的。