Node.js HTTP Server:建立原生的 Web 伺服器

Node.js 最著名的特性之一,就是它不依賴 Apache 或 Nginx 就能自行架設高效能的 Web 伺服器。雖然現代開發多使用 Express 等框架,但深入理解原生的 http 模組,對於掌握 Web 請求的底層邏輯與串流 (Stream) 運作至關重要。

建立第一個 Web 伺服器

只需要幾行程式碼,你的電腦就能瞬間轉化為一台伺服器,準備接收全球的請求。

const http = require('http');

// createServer 的回呼函式會在每次有請求進來時執行
const server = http.createServer((req, res) => {
  // 設定狀態碼與回應頭
  res.writeHead(200, { 'Content-Type': 'text/html; charset=utf-8' });

  // 寫入內容並正式結束回應
  res.end('<h1>你好!這是來自 Node.js 原生伺服器的訊息。</h1>');
});

server.listen(3000, () => {
  console.log('伺服器正運行在 http://localhost:3000/');
});

請求物件 (Request):客戶端傳了什麼?

req 物件是一個 Readable Stream。它承載了所有的連線資訊:

  • req.url:請求的路徑(如 /api/users)。
  • req.method:HTTP 方法(GET, POST, PUT, DELETE...)。
  • req.headers:存取所有的請求頭資訊(如 User-Agent, Cookie)。

回應物件 (Response):我要回覆什麼?

res 物件是一個 Writable Stream

  • res.writeHead():同時設定狀態碼與多個標頭(一旦呼叫就不能再改標頭)。
  • res.setHeader():個別設定標頭。
  • res.write():向客戶端傳送資料區塊(常用於大型串流傳輸)。
  • res.end():這一步是強制性的,用來告知伺服器回應已結束,否則客戶端會一直處於等待掛起狀態。

實戰:處理 POST 數據 (Body Parsing)

由於 req 是個串流,我們必須手動收集數據塊並拼接起來:

http
  .createServer((req, res) => {
    if (req.method === 'POST') {
      let body = '';

      // 監聽數據流入
      req.on('data', (chunk) => {
        body += chunk.toString();
      });

      // 數據接收完畢
      req.on('end', () => {
        const data = JSON.parse(body);
        console.log('收到 POST 資料:', data);
        res.end('資料已收到');
      });
    }
  })
  .listen(3000);

基本路由 (Simple Routing) 邏輯

在原生環境下,我們需要根據 req.url 進行手動分流:

const server = http.createServer((req, res) => {
  const path = req.url;

  if (path === '/' || path === '/home') {
    res.end('首頁內容');
  } else if (path === '/api/status') {
    res.writeHead(200, { 'Content-Type': 'application/json' });
    res.end(JSON.stringify({ status: 'Online' }));
  } else {
    res.writeHead(404);
    res.end('404 Not Found');
  }
});
為什麼要學 Express? 看到上面的路由與 Body 解析了嗎?在原生模式下做這些事非常繁瑣。這就是為什麼我們隨後會推薦使用 Express 框架,它能幫你自動化這些瑣碎的流程。

總結

  1. http.createServer 是 Node.js Web 開發的起點。
  2. 記得 res.end() 絕不能漏,它是關閉連線的訊號。
  3. 掌握原生 HTTP 模組後,你對 Node.js 的非阻塞 I/O 會有更深層次的體會。