iT邦幫忙

2025 iThome 鐵人賽

DAY 9
0
Modern Web

現在就學Node.js系列 第 9

HTTP 模組實戰 — 打造迷你伺服器 - Day9

  • 分享至 

  • xImage
  •  

HTTP 是什麼?

HTTP(HyperText Transfer Protocol,超文本傳輸協定)是一種 請求-回應模型 (Request/Response)

  • 客戶端(Client) → 發送請求(Request)
  • 伺服器(Server) → 接收並處理,最後回應(Response)

一個 HTTP 請求通常包含三個部分:

  1. Request Line(請求行) → 方法(GET、POST…)、路徑(如 /notes)、協定版本(HTTP/1.1、HTTP/2)
  2. Headers(標頭) → 提供額外資訊,例如 Content-TypeAuthorization
  3. Body(主體,可選) → 請求傳送的資料,常見於 POST / PUT,例如 JSON 或表單資料

👉 這種「請求 → 回應」的模式,就是網路世界溝通的核心。


HTTP 模組在 Node.js 的角色

Node.js 內建 http 模組,提供兩大功能:

  1. 建立伺服器http.createServer()
  2. 發送請求http.request()http.get()

換句話說,http 模組就像是 Node.js 和瀏覽器溝通的橋樑。

很多框架(例如 Express、Koa、Fastify)都是在這個基礎上進行封裝。

建立第一個伺服器

import http from "node:http";

// 1. 建立伺服器
const server = http.createServer((req, res) => {
  res.end("Hello from Node.js Server 🚀");
});

// 2. 監聽埠號(Port)
server.listen(3000, () => {
  console.log("伺服器運行中:http://localhost:3000");
});

步驟說明

  1. http.createServer()
    • 建立伺服器實例。
    • 傳入的 (req, res) 函式,當每次有請求時被執行。
    • req → 請求物件(method、url、headers…)
    • res → 回應物件(statusCode、headers、body…)
  2. server.listen(3000, ...)
    • 指定伺服器要監聽的埠號(port)。
    • Port 就像門牌號碼,讓外部知道怎麼找到服務。
      • 80 → HTTP 預設
      • 443 → HTTPS 預設
      • 3000/5000/8080 → 開發常用
    • 回呼函式會在伺服器啟動成功後執行,方便 debug。

請求流程示意圖

🧑‍💻 Client (Browser)
   │ 輸入 http://localhost:3000
   ▼
🌐 Node.js Server (http.createServer)
   │ 讀取 req.method, req.url, req.headers
   │ 處理邏輯
   │ 用 res.end() 回應
   ▼
📥 Client 收到回應 → 顯示 "Hello from Node.js Server 🚀"

📝 reqres 物件

每次有請求進來,Node.js 都會生成這兩個物件:

  • req(Request 請求物件)
    • req.method → HTTP 方法(GET、POST、PUT、DELETE…)
    • req.url → 請求路徑(/about/api
    • req.headers → 請求標頭資訊
  • res(Response 回應物件)
    • res.statusCode → 回應狀態碼(200 OK、404 Not Found…)
    • res.setHeader(name, value) → 設定回應標頭
    • res.end(data) → 結束回應並送出內容

HTTP 請求結構圖

這是一個 完整請求-回應流程

🧑‍💻 Client (Browser)
   │ 輸入網址 / 發送請求
   │
   ▼
📤 Request
   • Method: GET / POST
   • URL: /api
   • Headers: Content-Type, Authorization...
   • Body: JSON / Form Data (可選)
   │
   ▼
🌐 Node.js Server (http.createServer)
   • 讀 req.method, req.url, req.headers
   • 分析 body (若有)
   • 執行程式邏輯
   │
   ▼
📥 Response
   • Status Code (200, 404, 500…)
   • Headers (Content-Type: text/html, application/json…)
   • Body (HTML / JSON / 純文字)
   │
   ▼
🧑‍💻 Client 收到回應 → 渲染頁面 / 顯示資料


🌐 路由 (Routing) — 多頁面處理

const server = http.createServer((req, res) => {
  res.setHeader("Content-Type", "text/plain; charset=utf-8");

  if (req.url === "/") {
    res.end("🏠 首頁");
  } else if (req.url === "/about") {
    res.end("ℹ️ 關於我們");
  } else if (req.url === "/api") {
    res.setHeader("Content-Type", "application/json");
    res.end(JSON.stringify({ message: "Hello API", time: Date.now() }));
  } else {
    res.statusCode = 404;
    res.end("❌ 找不到頁面");
  }
});

👉 用 req.url 做判斷,就能決定回應什麼內容。這就是最基礎的「路由」。


⚠️ 編碼問題:為什麼要加上 charset=utf-8

如果只設定 Content-Type: text/plain,瀏覽器可能會用錯的編碼方式來解讀文字,

導致 中文或 emoji 亂碼

解法很簡單:

res.setHeader("Content-Type", "text/plain; charset=utf-8");

這樣就能保證所有文字正常顯示。

🔄 回應不同格式

JSON 回應(常用於 API)

if (req.url === "/api") {
  res.setHeader("Content-Type", "application/json");
  res.end(JSON.stringify({ message: "Hello API", time: Date.now() }));
}

HTML 回應(直接送網頁)

if (req.url === "/html") {
  res.setHeader("Content-Type", "text/html");
  res.end(`
    <html>
      <head><title>Node.js Server</title></head>
      <body><h1>Hello HTML 🌐</h1></body>
    </html>
  `);
}

迷你 API 伺服器

我們做一個小型伺服器,支援三種路由:

  • / → 首頁(文字)
  • /time → 現在時間 JSON
  • /hello → HTML
import http from "node:http";

const server = http.createServer((req, res) => {
  if (req.url === "/") {
    res.end("🏠 歡迎來到首頁");
  } else if (req.url === "/time") {
    res.setHeader("Content-Type", "application/json");
    res.end(JSON.stringify({ now: new Date().toISOString() }));
  } else if (req.url === "/hello") {
    res.setHeader("Content-Type", "text/html");
    res.end("<h1>Hello from Node.js 🌐</h1>");
  } else {
    res.statusCode = 404;
    res.end("❌ Not Found");
  }
});

server.listen(3000, () => {
  console.log("伺服器啟動:http://localhost:3000");
});

HTTP模組 第二個功能 - 發送 HTTP 請求

除了建立伺服器,http 模組也能讓 Node.js 發送 HTTP 請求

1) http.get() — 發送 GET 請求

import http from "node:http";

http.get("http://jsonplaceholder.typicode.com/todos/1", (res) => {
  let data = "";

  // 不斷接收資料
  res.on("data", (chunk) => {
    data += chunk;
  });

  // 全部接收完畢
  res.on("end", () => {
    console.log("伺服器回應:", JSON.parse(data));
    // 伺服器回應: { userId: 1, id: 1, title: 'delectus aut autem', completed: false }
  });
});

👉 適合用於快速發送簡單的 GET 請求。


2) http.request() — 發送更彈性的請求

import http from "node:http";

const options = {
  hostname: "jsonplaceholder.typicode.com",
  path: "/posts",
  method: "POST",
  headers: {
    "Content-Type": "application/json",
  },
};

const req = http.request(options, (res) => {
  let data = "";

  res.on("data", (chunk) => {
    data += chunk;
  });

  res.on("end", () => {
    console.log("回應:", JSON.parse(data));
  });
});

// 傳送請求 body
req.write(JSON.stringify({ title: "Hello", body: "World", userId: 1 }));
req.end();

👉 http.request() 支援 POST / PUT / DELETE 等需要帶 body 的請求。

已經說明與介紹完HTTP模組的兩個功能,建立伺服器以及發送請求,相信應該有更認識這模組了吧!

小結

今天了解到:

  1. HTTP 模組是:請求-回應模型
  2. Node.js http 模組能建立伺服器 & 發送請求
  3. req / res 物件的核心角色
  4. 如何透過 req.url 實作簡單路由
  5. 正確設定 Content-Type,避免亂碼問題
  6. 建立了一個可以回應文字 / JSON / HTML 的迷你伺服器

明天就是第十天了,預計要結合fs + path 模組
打造一個「靜態檔案伺服器」,可以送出 HTML、CSS、JS 和圖片,
讓 Node.js 真正成為一個小型 Web Server!


上一篇
事件驅動與 EventEmitter — Node.js 的事件世界 -Day8
系列文
現在就學Node.js9
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言