Back-End
Express
Middleware
本篇為 [BE201] 後端中階:Express 與 Sequelize 這門課程的學習筆記。如有錯誤歡迎指正!
在上一篇筆記 後端中階 - Node.js + Express 框架:建立一個靜態網頁,我們學到如何透過 Node.js 搭配 Express 框架,來快速建立一個靜態網頁。並瞭解到什麼是 MVC 架構,以及如何串接 MySQL 資料庫。
而 Express 的核心,其實就是由 Routing(路由系統)和 Middleware(中間介)兩個部分所組成。
也就是說,Express 會根據定義不同路由來執行接收到的 request,過程中會透過一連串的 middleware 處理,執行到最後產生 response。
接下來我們會針對 Middleware 的部分做介紹。
在 Express 開發框架中,middleware 扮演資料庫與應用程式之間的溝通橋樑,透過不同類別的 middleware,依照需求對資料進行不同處裡,讓資料傳遞更加便利。
例如先前範例中的 app.get('/todos', todoController.getAll)
,其實就可以看做是一個 middleware。
我們可透過 middleware function 傳入三個參數,然後輸出想要的資料:
舉個簡單的例子,在之前實作 todolist 的 index.js 中加入 app.use()
,代表整個程式都能使用這個 middleware:
重整瀏覽器頁面時,會發現畫面什麼東西都沒有:
但是在 CLI 介面會印出執行結果,每重整一次畫面就會執行 log 一次:
之所以沒有得到 response,是因為沒有加入第三個參數,也就是呼叫 next 把控制權轉移到下一個 middleware。可以把程式碼修改如下:
重整頁面後,就能看到經渲染過的畫面,同時 CLI 介面上也會印出接收 request 的時間:
這其實就是一個簡單的 middleware 應用。那這個機制實際上在 Express 有哪些用處呢?比如說,在 Express 程式中,並沒有內建解析透過 post method 的 request body、管理 session 機制等功能,就必須透過 middleware 來實現。
此外,middleware 處理是有順序性的。以一個簡單的權限管理機制為範例,例如網址列上必須有 admin
才能顯示頁面:
這個方法是透過 Express 內建的 .query
語法,來拿到網址列上的參數。
直接在兩個 Controllers 都加上 checkPermission() 進行權限驗證:
回到瀏覽器,會發現必須網址列加上 ?admin=1
參數才能讀取畫面:
這樣就完成簡單的權限驗證機制,但這其實不是一個好做法,一旦 function 變多就會不易管理。這種情況就是 middleware 登場的時候了!
在 index.js 加上 app.use(),並傳入 next 參數,若網址列通過驗證就會把控制權傳下去:
執行結果如下:
這其實就是 middleware 的作用,相較於方法一,我們能透過 middleware 來簡化程式碼。
此外,我們也能改寫上述程式碼,獨立出 checkPermission() 這個 function 來進行驗證:
這種寫法的好處,在於我們可以針對不同路由進行處理。例如加在 /todos
時,就只有這個路由會被影響:
在 /todos
這個路由,必須加上 ?admin=1
才能顯示畫面:
但是 /todos/:id
這個路由不會受到影響,因為沒有加上 checkPermission() 這個 middleware:
在上一篇筆記的 todolist 範例中,之所以沒有寫到 next 來轉移控制權,是因為處理完就回傳 response 資料,既然不會用到 next 這個參數,就可省略宣告。
接著要來介紹 body-parser 這個很常使用到的 middleware,使用方法可參考 GitHub 上 expressjs/body-parser 的範例。
body-parser 是一個用來解析解析 HTTP Request 的中間介。前面有提到說,我透過 Express 內建的語法,我們只能拿到 query string,因此只適用於 GET method,但若是 POST method 就必須透過 middleware 才能拿到 request body。
body-parser 根據不同語法,能夠處理下列幾種格式資料:
程式碼範例如下:
同樣以之前的 todolist 範例,繼續實作新增 todo 功能:
body-parser
套件,就可以使用 bodyParser() 處理 Request。接著在根目錄新增一個處理 addTodo 的路由:執行後可在瀏覽器確認是否有畫面:
這時如果點選提交,會跳轉到錯誤頁面,這是因為還沒有處理路由:
在瀏覽器提交表單,確認有拿到資料:
之所以能夠拿到表單提交的資料,是透過 body-parser 這個中間介解析 resquest body,才能拿取 content,否則程式會因為無法解析而出現錯誤。
回到瀏覽器確認是否能夠新增 todo:
這樣就完成一個簡單的 Back-end 專案了!並且有 MVC 架構,也就是 View 顯示畫面,Model 處理資料,Controller 藉由不同路由接收 requset,會執行相對應的 method;還有透過 body-parser 這個 middleware 處理 POST 表單提交的資料。
再來介紹 Express 框架中,用來管理 session 的中間介:express-session,使用方法可參考 GitHub 的 expressjs/session 頁面。
接著延續前面的 todolist 範例,實作一個簡單的登入功能。
執行結果:
這樣就透過 express-session 中間介提供的功能,完成簡單的登入登出功能。
但這種寫法其實會遇到一個問題,也就是每個 render 的頁面都要加上 isLogin 判斷登入狀態,我們再來要介紹的中間介就可以解決這個問題。
藉由 connect-flash 提供的 flash message 功能,我們就能在頁面顯示錯誤訊息等等,其實這背後的機制就是透過 session,能夠和 express-session 搭配使用。
使用方法可參考 GitHub 的 jaredhanson/connect-flash 頁面。
執行結果如下,當提交錯誤時會顯示 errorMessage,重整頁面後就會消失,這就是 flash 的功用:
但這種寫法其實還是不夠簡潔,如果要判斷輸出錯誤都還是要向 isLogin 那樣加上 errorMessage。
其實在 express 中有個捷徑,我們可以自己新增 middleware。也就是把東西存放在 res.locals
,view 就可以直接從 locals 存取使用,可想像成全域變數的感覺:
addTodo 的 Controller 也可以改回原本的:
修改完成之後,同樣能夠執行程式,透過範例整理兩個重點:
透過上述範例,我們能夠得知在使用 Express 框架實作網頁時,大致上會依照下方流程進行:
在接下來的課程,我們會綜合之前所學的知識,來實作簡單的會員註冊系統以及留言版功能。
參考資料: