這一課完成後:你會在本機啟動第一個 Node.js HTTP server,建立 GET /api/hello route,回傳 JSON,並能說明 frontend、backend、request、response、status code 與 route 各自扮演什麼角色。
先把「Web App」拆成兩邊
到目前為止,你主要寫的是 frontend:HTML、CSS、JavaScript 都會被送到瀏覽器,最後在使用者的裝置上執行。
Backend 則是另一個正在執行的程式。它通常跑在 server 環境,負責接 request、做規則判斷、讀寫 database、處理 authentication,再把結果回給 client。
Backend → HTTP Response → Browser / Frontend
注意:backend 不代表一定在「很遠的雲端」。今天它就跑在你的電腦上,只是使用不同 process 和 port。
建立新的 Web App 練習專案
不要繼續把東西塞進 Web Basics 專案。建立:
web-app-playground/
└─ server.js
用 VS Code 打開整個資料夾,再開 Terminal。
先確認:
node --version
能看到版本號再繼續。如果找不到 Node.js,先回 Start Here 的環境設定。
第一個 server:先只回一段文字
在 server.js:
const { createServer } = require("node:http");
const port = 3000;
const server = createServer((request, response) => {
response.writeHead(200, {
"Content-Type": "text/plain; charset=utf-8"
});
response.end("Hello from backend.");
});
server.listen(port, () => {
console.log(`Server running at http://localhost:${port}`);
});
執行:
node server.js
Terminal 不會立刻回到新的提示符號,因為這支程式不是「跑完就結束」;它會持續監聽 request。
現在真的去 request 它
瀏覽器打開:
http://localhost:3000
你會看到:
Hello from backend.
這句文字不是瀏覽器自己知道的,也不是寫在 HTML 裡。瀏覽器送了一個 HTTP request,你的 Node.js process 收到後建立 response。
localhost 和 port 到底是什麼?
localhost 指向目前這台電腦。現在 client 和 server 剛好都在同一台機器上。
3000 是 port,可以先把它理解成這台電腦上某個網路服務正在監聽的入口。
之後正式部署時,網址可能變成真正的 domain,但 request / response 的基本模型不會因此改變。
request 和 response 不是抽象名詞
在 handler 裡:
createServer((request, response) => {
// request:瀏覽器送進來的資訊
// response:你準備回出去的內容
});
request 會包含 method、URL、headers 等資訊;response 則讓你設定 status、headers 與 body。
先加:
console.log(request.method, request.url);
重新整理瀏覽器,你的 server Terminal 會看到類似:
GET /
/ → request path
Backend 不應該每個網址都回同一個東西
現在加入第一個真正的 route:
const { createServer } = require("node:http");
const port = 3000;
const server = createServer((request, response) => {
if (request.method === "GET" && request.url === "/api/hello") {
response.writeHead(200, {
"Content-Type": "application/json; charset=utf-8"
});
response.end(JSON.stringify({
message: "Hello from backend",
source: "Norelyn Learn"
}));
return;
}
response.writeHead(404, {
"Content-Type": "application/json; charset=utf-8"
});
response.end(JSON.stringify({
error: "Not found"
}));
});
server.listen(port, () => {
console.log(`Server running at http://localhost:${port}`);
});
重新啟動 server 後,打開:
http://localhost:3000/api/hello
你應該會看到 JSON。
為什麼要重新啟動 server?
目前我們直接用 node server.js。你修改檔案並儲存後,已經在執行中的 Node process 不會自動重新讀完整程式。
先在 Terminal 按:
Ctrl + C
停止 process,再重新:
node server.js
之後可以再使用 watch mode 或開發工具自動重啟;現在先把 process 的概念弄清楚。
Route 是「哪一種 request 要交給哪段邏輯」
這次的 route 條件是:
GET /api/hello
意思不是「有一個叫 API 的資料夾」。它只是你定義的 HTTP 介面。
下一課會把 route 擴充成多個資源,並開始接 query、body 和不同 HTTP methods。
Status code 也是 response 的一部分
成功 route 回:
200
找不到 route 則回:
404
這些不是給人看的裝飾數字,而是 client 判斷 request 結果的重要訊號。
你在 Web Basics 已經寫過:
if (!response.ok) {
throw new Error(...);
}
現在你站到 backend 這一側,開始負責決定什麼時候應該回成功、什麼時候應該回錯誤。
Content-Type 告訴 client:body 是什麼
回 JSON 時我們設定:
"Content-Type": "application/json; charset=utf-8"
然後:
JSON.stringify({ message: "Hello" })
因為 HTTP response body 最後要送的是位元組 / 文字內容,不是 JavaScript object 本身。
這和上一條路徑學的 response.json() 剛好是一來一回。
用 curl 看 request / response,不一定每次都開瀏覽器
保持 server 正在執行,再開另一個 Terminal:
curl http://localhost:3000/api/hello
你應該會拿到 JSON。
如果要看 response headers,可以試:
curl -i http://localhost:3000/api/hello
這會讓 status line、headers 與 body 一起出現。之後測 API 時,瀏覽器不是唯一工具。
故意打一個不存在的 route
打開:
http://localhost:3000/api/does-not-exist
你應該拿到:
{"error":"Not found"}
而且 status 是 404。
這件事很重要:backend 不只負責「成功時吐資料」,還要定義失敗時的行為。
Frontend code 和 Backend code 最大差別之一:執行位置
script.js 送到 browser 後,使用者能下載、查看並執行它。
server.js 則在 server process 裡執行,不需要被直接送給使用者。
Backend JS → Server runtime 執行
這也是為什麼 database credentials、server-side secret 之後應該留在 backend environment,而不是寫進公開前端。
但不要把「backend」理解成自動安全。如果你自己把 secret 放進 API response、log、錯誤訊息或公開 repository,它照樣會洩漏。執行位置只是邊界的一部分。
你的 backend 現在其實還沒有 database
目前 server 每次 response 都是程式碼當場組出來的。
如果你把:
let count = 0;
放進 server 記憶體,它也只會活到 process 結束為止。重新啟動後資料就回到初始狀態。
這就是後面 database 要解決的問題:讓重要資料不要跟著 process 一起消失。
小挑戰:自己加一個 status endpoint
需求 1:新增 GET /api/status。
需求 2:回傳 JSON,不是純文字。
需求 3:至少包含 ok: true 和一個你自己命名的欄位。
需求 4:不存在的 route 仍然必須維持 404。
需求 5:用瀏覽器或 curl -i 確認 status code 與 Content-Type。
不要把兩個 route 寫成「不管 URL 是什麼都回 status」。你的 server 要真的根據 method + path 做不同決定。
最後收斂:你剛才建立的不是一個頁面
你建立的是一個持續執行、等待外部 request 的程式:
↓ listen port 3000
收到 HTTP request
↓ route 判斷
執行 backend logic
↓ HTTP response
Frontend 之後只是其中一種 client。手機 App、另一個 server、CLI,甚至測試工具都可以呼叫同一個 HTTP API。
下一課會讓 API 不只「回固定資料」,而是開始讀 request 裡的 path、query 和 body,處理真正的輸入。
完成條件:你能獨立啟動一個 Node.js HTTP server,建立至少兩個 GET routes,正確回傳 JSON 與 404,並能解釋 request、response、route、status code、frontend 與 backend 的關係。