iT邦幫忙

2026 iThome 鐵人賽

DAY 23
0
JavaScript

不要再說你不會後端!30 天 Node.js 降維打擊指南 系列 第 23 篇

Day 23:中介軟體 (Middleware) 實戰與錯誤處理機制

  • 分享至 

  • xImage
  •  

進入 Express.js 的靈魂深處!前幾天我們一直在寫路由 (Routes),但你有沒有想過:如果我有 50 個需要「登入後才能存取」的 API,難道我要在每個路由裡面都寫一遍 JWT 驗證邏輯嗎?

這時候,就是 中介軟體 (Middleware) 登場的時刻了。

1. 什麼是中介軟體?

把 Express 伺服器想像成一條「機場安檢通道」。
使用者發出請求 (Request) 後,在到達最終目的地 (Response) 之前,可以設置一道又一道的關卡,這些關卡就是 Middleware。

每個 Middleware 都可以:

  1. 偷看、修改 req 或 res 的資料。
  2. 直接提早結束回應 (例如發現沒有票,直接趕出去)。
  3. 呼叫 next(),把使用者放行到下一關。

** 絕對鐵則**:在 Middleware 裡,你要麼回傳 res.send() 結束這回合,要麼呼叫 next()。如果兩個都不做,使用者的畫面就會一直轉圈圈卡死。

2. 實作:打造專屬的 JWT 守衛

我們來寫一個「身分驗證守衛」。只有帶著合法 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 無效或已過期' });
    }
};

3. 如何使用這個守衛?

回到你的路由檔案 (例如 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;

4. 終極防護網:全域錯誤處理 (Global Error Handler)

你的 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 伺服器已經具備了強壯的骨架,足以應對各種複雜的商業邏輯與異常狀況了。


上一篇
Day 22:伺服器的終極防禦(密碼加密 Bcrypt 與環境變數 dotenv)
系列文
不要再說你不會後端!30 天 Node.js 降維打擊指南 共 23 篇
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言