iT邦幫忙

2025 iThome 鐵人賽

DAY 17
0
自我挑戰組

《轉職學習日記:JavaScript × Node.js × TypeScript × Docker × AWS ECS》系列 第 17

Day17 - 持續成長學習藍圖 - Node.js(錯誤處理與日誌紀錄)

  • 分享至 

  • xImage
  •  

昨天我把 Todo API 接上了 PostgreSQL,讓資料可以真正存進資料庫。
不過 API 還有一個大問題:如果出錯,沒有好好處理,整個伺服器就會回傳一個很醜的錯誤訊息,甚至直接掛掉。
今天的重點就是補上 錯誤處理日誌紀錄,讓 API 更穩健。


1. 為什麼需要錯誤處理?

想像以下情境:

  • 使用者傳錯參數 → API 直接壞掉?
  • 資料庫連不到 → 伺服器崩潰?
  • 程式碼寫錯 → 螢幕上只看到一堆紅字?

這些情況如果沒有被捕捉,就會變成 500 Internal Server Error,使用者完全不知道發生什麼事。
正確做法是:捕捉錯誤 → 回傳清楚的訊息 → 記錄 Log


2. Express 的錯誤處理 Middleware

Express 提供一個特別的 Middleware,只要有 (err, req, res, next) 這四個參數,就能捕捉錯誤。

app.use((err, req, res, next) => {
  console.error("發生錯誤:", err.message);
  res.status(500).json({ error: "伺服器錯誤,請稍後再試" });
});

這樣一來,只要在程式裡用 next(err) 或丟出錯誤,Express 都會進到這個錯誤處理器。


3. 加入日誌紀錄(morgan)

Log(紀錄)可以幫助我們在開發與維運時追蹤問題。
最簡單的做法是用 morgan

npm install morgan
import morgan from "morgan";
app.use(morgan("dev"));

這樣每次請求都會輸出像這樣的 log:

GET /todos 200 15 - 2.345 ms
POST /todos 201 42 - 3.112 ms

4. 整合錯誤處理與日誌

延續昨天的 app.js,我幫 Todo API 加上錯誤處理:

import express from "express";
import { pool } from "./db.js";
import morgan from "morgan";

const app = express();
const port = 3000;

app.use(express.json());
app.use(morgan("dev"));

// GET /todos
app.get("/todos", async (req, res, next) => {
  try {
    const result = await pool.query("SELECT * FROM todos ORDER BY id ASC");
    res.json(result.rows);
  } catch (err) {
    next(err); // 把錯誤丟給錯誤處理器
  }
});

// POST /todos
app.post("/todos", async (req, res, next) => {
  try {
    const { task } = req.body;
    if (!task) {
      return res.status(400).json({ error: "task 欄位必填" });
    }

    const result = await pool.query(
      "INSERT INTO todos (task) VALUES ($1) RETURNING *",
      [task]
    );
    res.status(201).json(result.rows[0]);
  } catch (err) {
    next(err);
  }
});

// 錯誤處理 Middleware
app.use((err, req, res, next) => {
  console.error("❌ 發生錯誤:", err.stack);
  res.status(500).json({ error: "伺服器錯誤,請稍後再試" });
});

app.listen(port, () => {
  console.log(`伺服器啟動:http://localhost:${port}`);
});

5. 測試錯誤情境

(1) 傳錯參數

curl -X POST http://localhost:3000/todos \
  -H "Content-Type: application/json" \
  -d '{}'

輸出:

{ "error": "task 欄位必填" }

(2) 模擬資料庫錯誤(亂改 SQL)

SELECT * FROM todos 改成 SELECT * FROM not_exist → 伺服器會輸出:

❌ 發生錯誤: error: relation "not_exist" does not exist

而客戶端只會收到:

{ "error": "伺服器錯誤,請稍後再試" }

這樣一來,使用者不會看到內部細節,但我們還是能在 log 裡看到真實的錯誤。


🎯 學習心得 / 今日收穫

今天最大的收穫就是:API 不只是能跑,還要能「優雅地出錯」

  • 錯誤處理 Middleware 可以集中管理錯誤,避免程式亂掉。
  • morgan 幫我自動記錄請求 log,之後要 debug 或觀察效能都很方便。
  • 錯誤要「對使用者簡單明瞭」,「對開發者詳細完整」,這是好的 API 體驗。

到目前為止,我的 Todo API 已經有 CRUD、能連資料庫、能處理錯誤與紀錄 log。


上一篇
Day16 - 持續成長學習藍圖 - Node.js(連接資料庫 – PostgreSQL 基礎)
下一篇
Day18 - 持續成長學習藍圖 - Node.js(小作品_Todo API 整合)
系列文
《轉職學習日記:JavaScript × Node.js × TypeScript × Docker × AWS ECS》20
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言