Express 中間件 (Middleware):核心運作機制與生命週期
Middleware (中間件) 是 Express 的靈魂。在 Express 的架構中,幾乎所有的功能——從日誌記錄、權限驗證到請求解析——都是透過一個個中間件函數連接而成的「流水線」來實現的。
什麼是 Middleware?
我們可以將 Middleware 想像成加工廠裡的處理站。當一個 HTTP 請求進入 Express 應用後,它會依次經過你定義的處理站,最後才達成目標路由並發出回應。
一個中間件函數具備三個核心參數:(req, res, next)。
req:請求物件,你可以往裡面新增自定義屬性。res:回應物件,任何一個中間件都可以決定在這裡提前結束請求。next:這是一個控制函式。呼叫next()代表「我處理完了,交給下一個處理站」。
實戰:建立自定義中間件
1. 全域日誌系統
我們希望每個請求進來時,都記錄它的連線時間與耗時。
const express = require('express');
const app = express();
const requestLogger = (req, res, next) => {
const start = Date.now();
// 監聽回應結束事件
res.on('finish', () => {
const duration = Date.now() - start;
console.log(`[${req.method}] ${req.url} - ${duration}ms`);
});
next(); // 務必呼叫,否則請求會永遠掛起 (Pending)
};
app.use(requestLogger);
2. 特定路由的權限驗證
中間件也可以只掛載在特定的路徑上。
const checkAdmin = (req, res, next) => {
if (req.headers['x-admin-key'] === 'secret123') {
next();
} else {
res.status(403).json({ error: '您沒有存取此 API 的權限' });
}
};
app.get('/api/admin/config', checkAdmin, (req, res) => {
res.send('這是敏感的配置資料');
});
重要觀念:掛載順序的重要性
Express 執行中間件的順序與你在程式碼中撰寫 app.use() 的順序完全一致。
app.use(middlewareA);
app.use(middlewareB);
app.get('/', (req, res) => {
// A 會比 B 先執行
});
如果你在一個中間件中 res.send() 了回應,那麼後續的中間件將不會被執行。
錯誤處理中間件 (Error Handling)
這是一種特殊的中間件,它接收 四個 參數:(err, req, res, next)。Express 會自動識別這種簽章,並在有錯誤發生時跳過普通中間件直接進入這裡。
app.use((err, req, res, next) => {
console.error('系統發生異常:', err.stack);
res.status(500).send('伺服器出問題了,請稍候再試');
});
黃金準則:在中間件中,你必須執行以下兩者之一:
- 呼叫
next()將控制權傳下去。 - 呼叫
res.send()等方法結束這次請求。 如果兩者都沒做,瀏覽器將會一直轉圈直到連線逾時。
總結
- Middleware 構築了 Express 靈活的插件式架構。
next()是驅動流水線前進的齒輪。- 掌握中間件的 掛載順序 是排查 Bug 的第一步。