
唉呀,今天院子裡的風吹得真舒服,茶杯裡的琥珀熱茶還溫著呢。看著我的大孫女在一旁安安靜靜地看書,小孫女卻嘟著嘴、抱著筆電跑過來跟我撒嬌,說學校的全端程式作業怎麼寫都不會動。
阿公摸了摸她的頭,接過筆電一看,原來又是被卡在那些囉哩囉唆的環境設定,和什麼「CORS」的安全防護上了。現在的孩子們要學全端開發真是不容易,還沒開始寫到最核心的邏輯,熱情就被這堆雜事澆熄了。
既然這樣,阿公今天不講以前鄉下的老故事,我們來聊聊怎麼用最乾淨、最不拖泥帶水的方法,建構出這台會發出炫麗霓虹彩色光的『Cyber-Neon Todo List』吧。坐好,喝口熱茶,聽阿公慢條斯理地跟你道來……
小孫女剛才抱著筆電哭喪著臉,這也是好多初學全端開發的人最常遇到的困難:
阿公常說,這就像下田耕作一樣,如果犁田的工具太重、手續太繁雜,種子還沒播下去,人都累垮了。所以,我們要用極簡主義的智慧,排除這些無謂的障礙,讓大家能專注在程式碼的「核心邏輯」上。
這套「Cyber-Neon Todo List」雖然外表有著極具未來感的賽博朋克霓虹美學(深色漸層背景、玻璃擬態卡片、霓虹文字與按鈕光暈效果),但在系統架構上,阿公幫你們挑選了最乾淨、最不佔空間的極簡組合:
/docs 幫你生成一份活生生的說明書,可以直接在上面按按鈕測試,省去寫文件的麻煩。阿公做事講求規矩,家裡的工具間要整理得井井有條,程式碼也是。這個專案採用嚴格的前後端分離模組化目錄結構,讓每一支檔案都有它專屬的職責:
/project-root
├── backend/ # 後端 FastAPI 專案
│ ├── app/
│ │ ├── models/ # SQLAlchemy 資料庫模型
│ │ │ ├── __init__.py # 模型匯出索引
│ │ │ └── todo.py # 定義 Todo 的資料表結構
│ │ ├── schemas/ # Pydantic 驗證 Schema (分開 Create/Response)
│ │ │ └── todo.py
│ │ ├── routers/ # API 路由邏輯 (處理 HTTP 請求)
│ │ │ └── todo.py
│ │ ├── database.py # SQLite 連線設定
│ │ └── main.py # 後端伺服器入口
│ └── pyproject.toml # 後端依賴管理
├── frontend/ # 前端 Express 專案
│ ├── public/ # 靜態網頁資源
│ │ ├── css/
│ │ │ └── style.css # 賽博朋克霓虹風格與動效
│ │ ├── js/
│ │ │ ├── api.js # 封裝好的 Fetch API 呼叫工具
│ │ │ └── main.js # 前端 DOM 互動與邏輯處理
│ │ └── index.html # 結構化的主要網頁
│ ├── server.js # 輕量 Express 靜態伺服器
│ └── package.json # 前端依賴管理
├── start_all.sh # Mac/Linux 一鍵啟動腳本
└── start_all.bat # Windows 一鍵啟動腳本
小孫女問我:「阿公,我們每次要開這台待辦清單,是不是要開兩個黑黑的視窗(終端機)手動打指令?那多累人啊。」
阿公教你,我們可以寫一個一鍵啟動腳本。只要輕輕點兩下,它就會自動幫我們處理好兩件大事:
main.py 裡面使用了 FastAPI 的 lifespan 事件。當後端一啟動時,它就會自動去偵測本機有沒有 SQLite 檔案,如果沒有,會自動幫你建立資料表,完全不需要手動去跑任何 SQL 建表指令!Port 8000)與前端的 Express 伺服器(運作在 Port 3000),我們只需要打開瀏覽器訪問 http://localhost:3000 就可以開始使用了!start_all.bat)範例:
@echo off
echo 正在啟動賽博霓虹待辦清單全端服務...
start cmd /k "cd backend && uv run uvicorn app.main:app --reload --port 8000"
start cmd /k "cd frontend && node server.js"
echo 服務已啟動!
echo 請存取前端網頁: http://localhost:3000
echo 請存取 API Swagger 文件: http://localhost:8000/docs
當我們在本地端進行前後端分離部署時(前端在 Port 3000 伺服網頁,後端在 Port 8000 提供 API 服務),如果直接用 JavaScript 去呼叫 API,瀏覽器就會跳出錯誤,拒絕讀取資料。
這就叫做 CORS(跨來源資源共用,Cross-Origin Resource Sharing) 限制。
這堵牆是瀏覽器的安全保護機制,怕外面的壞人隨便跑來偷拿你的資料。因為網頁在 3000 埠,API 在 8000 埠,對瀏覽器來說,這兩個就是「不同的來源(Origin)」,所以它預設會直接封鎖前端的 API 請求。
要解決這個痛點,我們必須在後端 FastAPI 入口(backend/app/main.py)中,明確告訴後端:「這個 Port 3000 的前端是我們自己家的人,請放行讓他進來。」
阿公幫你們寫好了這段關鍵程式碼,在初始化 FastAPI 的時候,一定要加上這段 CORS 中間件:
from fastapi import FastAPI
from fastapi.middleware.cors import CORSMiddleware
app = FastAPI(title="Cyber-Neon Todo API")
# 1. 定義允許存取的來源清單(明確指定我們的前端 Port 3000)
origins = [
"http://localhost:3000",
"http://127.0.0.1:3000",
]
# 2. 將 CORSMiddleware 註冊到 FastAPI 應用中
app.add_middleware(
CORSMiddleware,
allow_origins=origins, # 允許這些來源進行跨網域存取
allow_credentials=True, # 允許攜帶憑證(Cookie 等)
allow_methods=["*"], # 允許所有的 HTTP 方法(GET, POST, DELETE 等)
allow_headers=["*"], # 允許所有的 HTTP 標頭
)
# 之後再引入路由
# app.include_router(todo.router)
這樣一來,後端就會在 HTTP 回應中自動加上允許跨網域存取的標頭,瀏覽器看到這個標頭,就知道這是安全的,前端的 api.js 就能順順利利地拿到待辦清單的資料了!
喝乾了杯裡的最後一口熱茶,太陽也快下山了。
寫程式啊,有時候就像在院子裡除草、整地,雖然一開始會遇到硬石頭(環境設定不通、CORS 報錯),但只要我們把工具(FastAPI、SQLite、一鍵啟動腳本)準備好、把規矩定清楚,就能用最省力、最優雅的方式,開闢出一片屬於自己的賽博霓虹花園。
孫女聽懂了,笑嘻嘻地抱著筆電回去寫程式了。你們這些年輕的孩子們,也快點去動手試試看吧!