0%

Node.js - middleware 基礎介紹

node

middleware 中介軟體

官網說明:

Express 是一個本身功能極簡的路由與中介軟體 Web 架構:本質上,Express 應用程式是一系列的中介軟體函數呼叫。中介軟體函數是一些有權存取要求物件 (req)回應物件 (res) 和應用程式要求/回應循環中之下一個中介軟體函數的函數。下一個中介軟體函數通常以名為 next 的變數表示。

中介軟體函數可以執行下列作業:

  • 執行任何程式碼。
  • 對要求和回應物件進行變更。
  • 結束要求/回應循環。
  • 呼叫堆疊中的下一個中介軟體函數。
  • 如果現行中介軟體函數不會結束要求/回應循環,它必須呼叫 next()

使用 app.use()app.METHOD() 函數,將應用程式層次的中介軟體連結至 app object 實例,其中 METHOD 是中介軟體函數要處理的 HTTP 要求方法(例如 GET、PUT 或 POST),並採小寫。

如果有點抽象的話,可以當作 middleware 是一個守衛,可以顧及程式碼安全,所以 middleware 裡面可以寫一些安全性的程式邏輯,聽過 middleware 的把關後才會進入主要的程式碼。

基礎範例:

1
2
3
4
5
6
var app = express();

app.use(function (req, res, next) {
console.log("Time:", Date.now());
next(); // 一定要加這個函式才會往下處理
});

範例練習

首先先登打下方程式碼,

app.js

1
2
3
4
5
6
7
8
9
10
11
12
13
14
const express = require("express");
const app = express();

app.use((req, res, next) => {
console.log("這是 middleware");
next();
});

app.get("/", (req, res) => {
res.send("<h1>這是 middleware 練習</h1>");
});

const port = process.env.port || 3000;
app.listen(port);

並在終端機運作 node app.js,並且開啟 localhost:3000

會在終端機看到下方資訊:

terminal

md01

瀏覽器會看到:

browser

md02

可以看到會先讀到 middleware 的程式碼後,再執行 res 的內容在網頁上,相對的如果把 middleware 放在主要程式碼後面,那就失去 middleware 的功能。

404 頁面錯誤

為了提醒使用者可能輸入的路徑錯誤,所以現在網頁一定都要做 404 的錯誤頁面,可以看到會正確顯示頁面的是在根目錄的路由,如果路由任意輸入:

1
http://localhost:3000/thisiserrorurl

並且跑下方程式碼:

app.js

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
const express = require("express");
const app = express();

app.use((req, res, next) => {
console.log("這是 middleware");
next();
});

app.get("/", (req, res) => {
res.send("<h1>這是 middleware 練習</h1>");
});

// 404
app.use((req, res, next) => {
res.status(404).send("404 Oops! 找不到網頁!");
});

const port = process.env.port || 3000;
app.listen(port);

這邊運作的過程會是,先透過 middleware 確認登入以及驗證通過後,發現沒有可以配對的路由,所以會直接跳到 404 的程式碼區塊,並且在網頁上顯示 404 Oops! 找不到網頁! 的字樣。

browser

404

dev tool Network

透過開發人員工具也會看到 404 的錯誤訊息。

404

500 error 程式錯誤

假設程式發生錯誤,例如在 middleware 有個未定義的函式(此範例是要演譯如果程式錯誤的情境,正規並不會這樣做,但可能會遇到 XD)。

app.js

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
const express = require("express");
const app = express();

app.use((req, res, next) => {
console.log("這是 middleware");
notDefined(); // 執行一個沒有定義的函式
next();
});

app.get("/", (req, res) => {
res.send("<h1>這是 middleware 練習</h1>");
});

//404
app.use((req, res, next) => {
res.status(404).send("404 Oops! 找不到網頁!");
});

const port = process.env.port || 3000;
app.listen(port);

執行後畫面會變這樣,

browser

500 msg

但如果這樣呈現會被客戶打爆…

而 Express 也處理得很好,加上 500 error 的程式碼,

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
const express = require("express");
const app = express();

app.use((req, res, next) => {
console.log("這是 middleware");
notDefined(); // 執行一個沒有定義的函式
next();
});

app.get("/", (req, res) => {
res.send("<h1>這是 middleware 練習</h1>");
});

//404
app.use((req, res, next) => {
res.status(404).send("404 Oops! 找不到網頁!");
});

//500
app.use((err, req, res, next) => {
res.status(500).send("500 程式錯誤,請聯繫 IT 人員協助!");
});
const port = process.env.port || 3000;
app.listen(port);

此時重整畫面,網址與路徑還是要維持 localhost:3000/thisiserrorurl,並且會看到畫面為:

browser

500 browser

再看到 Network 也會出現 500 的資訊。

Network

500 network

middleware 可以獨立出來共用

如果 middleware 有需要共用的話,可以獨立拉出來變成一個函式,並且放在要執行的方法來讀取,得到的結果也會跟一開始的練習相同,程式碼如下:

app.js

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
const express = require("express");
const app = express();

// 拉出來變共用函式
function middleware(req, res, next) {
console.log("這是 middleware");
next();
}

// 放在有路徑的第二個參數
app.get("/", middleware, (req, res) => {
res.send("<h1>這是 middleware 練習</h1>");
});

//404
app.use((req, res, next) => {
res.status(404).send("404 Oops! 找不到網頁!");
});

//500
app.use((err, req, res, next) => {
res.status(500).send("500 程式錯誤,請聯繫 IT 人員協助!");
});

const port = process.env.port || 3000;
app.listen(port);