把 Express 伺服器想像成一條「機場安檢通道」。
使用者發出請求 (Request) 後,在到達最終目的地 (Response) 之前,可以設置一道又一道的關卡,這些關卡就是 Middleware。
每個 Middleware 都可以:
req 或 res 的資料。next(),把使用者放行到下一關。** 絕對鐵則**:在 Middleware 裡,你要麼回傳 res.send() 結束這回合,要麼呼叫 next()。如果兩個都不做,使用者的畫面就會一直轉圈圈卡死。
我們來寫一個「身分驗證守衛」。只有帶著合法 JWT 通行證的請求,才能通過這關。
在專案中新增一個資料夾 middlewares,並建立 auth.js:
import jwt from 'jsonwebtoken';
import 'dotenv/config';
// 這就是一個標準的 Middleware 函式 (多了第三個參數 next)
export const verifyToken = (req, res, next) => {
// 1. 從請求標頭 (Headers) 中取得 Authorization 欄位
// 慣例上,前端傳送 Token 的格式會是: "Bearer xxxxx.yyyyy.zzzzz"
const authHeader = req.headers.authorization;
if (!authHeader || !authHeader.startsWith('Bearer ')) {
return res.status(401).json({ message: '拒絕存取:未提供有效的 Token' });
}
// 2. 把 "Bearer " 切掉,只留下 Token 字串
const token = authHeader.split(' ')[1];
try {
// 3. 驗證 Token
const decoded = jwt.verify(token, process.env.JWT_SECRET);
// 4. 關鍵魔法:把解碼後的使用者資料,塞進 req 裡面!
// 這樣後面的路由就可以直接用 req.user 知道現在是誰在操作了
req.user = decoded;
// 5. 驗證成功,放行到下一關!
next();
} catch (error) {
return res.status(403).json({ message: '拒絕存取:Token 無效或已過期' });
}
};
回到你的路由檔案 (例如 routes/users.js),你只需要把守衛「安插」在網址和處理函式之間!
import express from 'express';
import { verifyToken } from '../middlewares/auth.js'; // 引入守衛
const router = express.Router();
// 【公開 API】任何人都可以看
router.get('/public-info', (req, res) => {
res.json({ message: '這是一般公開資訊' });
});
// 【受保護 API】安插 verifyToken 作為第二個參數!
router.get('/profile', verifyToken, (req, res) => {
// 因為前面的 Middleware 已經把使用者資料塞進 req.user 了
// 我們在這裡可以直接拿來用!
res.json({
message: '這是機密個人檔案',
userData: req.user
});
});
export default router;
你的 API 難免會發生預期外的崩潰 (例如資料庫斷線、語法寫錯)。如果不處理,Node.js 預設會把一堆可怕的錯誤堆疊 (Stack Trace) 直接噴給前端,甚至導致伺服器當機。
Express 提供了一個專門捕捉全域錯誤的特製 Middleware (特徵是它有 四個參數)。
請把它放在 app.js 的 最底部 (在所有路由之後):
// ... 上面是各種 app.use(路由)
// 404 處理 (當上面的路由都找不到時,就會掉到這裡)
app.use((req, res, next) => {
res.status(404).json({ message: '找不到此 API 路由' });
});
// 全域錯誤捕捉 Middleware (參數順序很重要:err, req, res, next)
app.use((err, req, res, next) => {
console.error(" 伺服器發生錯誤:", err.message);
// 回傳統一格式的錯誤訊息給前端
res.status(500).json({
message: '伺服器內部錯誤,請稍後再試',
error: process.env.NODE_ENV === 'development' ? err.message : {} // 只有開發模式才噴詳細錯誤
});
});
app.listen(PORT, () => {
console.log(`伺服器啟動於 PORT ${PORT}`);
});
恭喜你!有了 Auth Middleware 與 Global Error Handler,你的 Express 伺服器已經具備了強壯的骨架,足以應對各種複雜的商業邏輯與異常狀況了。