本文 AI 產出,尚未審核

ExpressJS (TypeScript) – 建立 HTTP Server


簡介

在現代 Web 開發中,Express 仍是 Node.js 生態系最常被採用的輕量級框架。它提供了直觀的路由、middleware 機制以及與各種第三方套件的良好整合,使得建立 RESTful API 或簡易網站變得非常快速。

將 Express 與 TypeScript 結合,不僅能享受 JavaScript 的彈性,還能透過靜態型別檢查提前捕捉錯誤、提升 IDE 補完與程式碼可讀性。對於剛踏入後端開發的同學,掌握「如何用 TypeScript 建立一個最基本的 Express HTTP Server」是邁向完整全端開發的重要第一步。

本篇文章將從環境安裝、專案初始化、基本伺服器寫法,到路由、middleware、錯誤處理的實作,提供 3~5 個實用範例,並說明常見的陷阱與最佳實踐,最後列出實務上常見的應用情境,幫助你快速上手並在專案中落地。


核心概念

1️⃣ 安裝與專案初始化

在開始寫程式前,我們先建立一個乾淨的 TypeScript + Express 專案。

# 建立資料夾並進入
mkdir my-express-app && cd my-express-app

# 初始化 npm,產生 package.json
npm init -y

# 安裝核心套件
npm i express
npm i -D typescript ts-node @types/node @types/express

接著建立 tsconfig.json,讓編譯器知道我們的目標環境。

{
  "compilerOptions": {
    "target": "ES2022",          // 使用最新的 JavaScript 標準
    "module": "commonjs",        // Node.js 預設模組系統
    "strict": true,              // 啟用嚴格模式,提升型別安全
    "esModuleInterop": true,     // 允許 import express from "express"
    "outDir": "./dist",          // 編譯後的檔案放置目錄
    "rootDir": "./src"
  },
  "include": ["src"]
}

小技巧:在 package.json 加入 "start": "ts-node src/index.ts",即可直接 npm start 執行開發環境。


2️⃣ 建立最簡單的 Express Server

以下程式碼示範最基礎的 HTTP Server,只回傳「Hello, World!」給所有請求。

// src/index.ts
import express, { Request, Response } from "express";

const app = express();               // 建立 Express 應用實例
const PORT = process.env.PORT || 3000;

// 根路由 GET 請求
app.get("/", (req: Request, res: Response) => {
  res.send("Hello, World! 🌏");
});

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

說明

  • express() 會回傳一個 Application 物件,我們可以在上面掛載路由、middleware。
  • app.get() 只處理 GET 方法,第一個參數是路徑,第二個是處理函式。
  • res.send() 會自動依內容類型設定 Content-Type,此例回傳純文字。

3️⃣ 加入 TypeScript 型別與環境設定

在大型專案中,我們往往會把路由、設定、錯誤處理分離成不同檔案。以下示範如何使用 interface 為請求參數加上型別,讓 IDE 能提供自動補完。

// src/routes/user.ts
import { Router, Request, Response } from "express";

interface UserParams {
  id: string;               // 期待的路由參數型別為字串
}

const router = Router();

// 取得單一使用者資訊
router.get("/user/:id", (req: Request<UserParams>, res: Response) => {
  const { id } = req.params;           // id 已被正確推斷為 string
  // 假設從資料庫取得使用者
  const user = { id, name: "Alice", age: 30 };
  res.json(user);
});

export default router;

在主程式中掛載此路由模組:

// src/index.ts
import express from "express";
import userRouter from "./routes/user";

const app = express();
app.use(express.json());          // 解析 JSON body
app.use("/api", userRouter);      // 所有 /api 前綴的請求交給 userRouter

app.listen(3000, () => console.log("Server ready"));

重點:使用 Request<Params>Response<ResBody>型別安全 成為開發的默認行為。


4️⃣ Middleware:請求前置處理

Middleware 是 Express 的核心概念,允許在請求到達路由前先執行共通邏輯,例如 日誌、驗證、CORS

// src/middleware/logger.ts
import { Request, Response, NextFunction } from "express";

export function logger(req: Request, res: Response, next: NextFunction) {
  const now = new Date().toISOString();
  console.log(`[${now}] ${req.method} ${req.path}`);
  next();                     // 必須呼叫 next() 才會繼續往下走
}

index.ts 中全域掛載:

import { logger } from "./middleware/logger";

app.use(logger);               // 所有路由皆會先走 logger

若要只針對特定路由套用,可在路由檔案內直接寫:

router.post("/login", logger, (req, res) => {
  // 登入處理...
});

5️⃣ 錯誤處理與伺服器優雅關閉

Express 允許自訂錯誤處理函式,簽名必須有四個參數 (err, req, res, next)

// src/middleware/errorHandler.ts
import { Request, Response, NextFunction } from "express";

export function errorHandler(
  err: Error,
  _req: Request,
  res: Response,
  _next: NextFunction
) {
  console.error("❗️", err);
  res.status(500).json({ message: "內部伺服器錯誤", error: err.message });
}

在所有路由之後掛載:

import { errorHandler } from "./middleware/errorHandler";

app.use(errorHandler);

優雅關閉:在開發或部署環境,最好在收到 SIGINT / SIGTERM 時先關閉伺服器,避免未完成的請求被截斷。

const server = app.listen(PORT, () => console.log(`Listening on ${PORT}`));

process.on("SIGINT", () => {
  console.log("\nGracefully shutting down...");
  server.close(() => {
    console.log("Server closed");
    process.exit(0);
  });
});

常見陷阱與最佳實踐

陷阱 可能的結果 建議的解法
忘記呼叫 next() 在 middleware 中 請求卡在中間層,客戶端永遠不會得到回應 每個非終結點的 middleware 必須 next(),或回傳 res.end()
直接在路由裡寫大量業務邏輯 代碼難以維護、測試困難 把業務抽離成 Service / Controller,路由只負責參數解析與回傳
未使用 express.json() 解析 JSON body req.body 會是 undefined,POST/PUT 失效 在所有路由前 app.use(express.json())
錯誤拋出未被捕獲 程式直接 crash,伺服器宕機 使用 try/catch + next(err),或全域錯誤處理 middleware
型別不一致 (例如 req.params.id 被當成 number) 編譯通過但執行時出錯 利用 TypeScript 的 interfacereq.paramsreq.body 明確指定型別

最佳實踐

  1. 分層架構routercontrollerservicerepository
  2. 環境變數 – 使用 dotenv 管理 PORTDB_URL 等設定,避免硬編碼。
  3. 日誌 – 以 morganwinston 替代手寫 console,支援等級與檔案輸出。
  4. 安全 – 加入 helmetcors,防止常見的 HTTP 攻擊。
  5. 測試 – 用 jest + supertest 撰寫單元與整合測試,確保路由行為不會因重構而斷裂。

實際應用場景

場景 為何選擇 Express + TypeScript
RESTful API 輕量、路由彈性、支援中介層,配合 TypeScript 可保障介面合約。
微服務 每個服務只需要一個簡單的 HTTP 入口,部署速度快,與 Docker/Kubernetes 配合無縫。
Server‑Side Rendering (SSR) 搭配 ejspugreact‑express,在同一個伺服器同時提供前端頁面與 API。
Webhook 接收端 如 GitHub、Stripe 等外部服務推送事件,Express 的 middleware 能快速驗證簽名。
開發測試環境 使用 ts-node-dev 即可在本機即時編譯、重新載入,省去繁雜的 Build 步驟。

總結

本文從 環境建置 → 基本 Server → 型別化路由 → Middleware → 錯誤處理,一步步示範了如何用 TypeScript 實作一個可靠且易於維護的 Express HTTP Server。掌握這套基礎後,你即可:

  • 以型別安全的方式撰寫路由與中介層,減少執行時錯誤。
  • 在專案中導入 分層架構環境變數日誌與安全,提升可讀性與部署品質。
  • 依照不同的實務需求(API、微服務、Webhook)快速擴展或調整。

只要持續將 最佳實踐 內化於日常開發,你的 Express 專案將會在可維護性、效能與安全性上都保持良好狀態。祝開發順利,期待在你的下一個專案裡看到更加完整與強大的 Express+TypeScript 應用!