靜態檔案處理
FastAPI 通常透過 Starlette 提供的 `StaticFiles` 來處理靜態檔案,例如 CSS、JavaScript、圖片與下載檔案。
## 1. 專案結構
例如:
```text
project/
├── main.py
├── static/
│ ├── hello.txt
│ ├── css/
│ │ └── style.css
│ └── index.html
└── tests/
└── test_static.py
```
`static/hello.txt` 內容:
```text
Hello FastAPI
```
---
## 2. 掛載靜態檔案目錄
`main.py`:
```python
from pathlib import Path
from fastapi import FastAPI
from fastapi.staticfiles import StaticFiles
BASE_DIR = Path(__file__).resolve().parent
STATIC_DIR = BASE_DIR / "static"
app = FastAPI()
app.mount(
"/static",
StaticFiles(directory=str(STATIC_DIR)),
name="static",
)
@app.get("/")
def read_root():
return {"message": "API is running"}
```
啟動:
```bash
uvicorn main:app --reload
```
之後可以透過以下網址存取:
```text
http://127.0.0.1:8000/static/hello.txt
http://127.0.0.1:8000/static/css/style.css
http://127.0.0.1:8000/static/index.html
```
### URL 對應關係
```text
/static/hello.txt
```
會對應到:
```text
static/hello.txt
```
`app.mount()` 中的:
```python
app.mount("/static", ...)
```
表示所有 `/static` 開頭的請求,都交給 `StaticFiles` 處理。
---
## 3. 支援 HTML 首頁
如果希望存取:
```text
http://127.0.0.1:8000/static/
```
時自動回傳 `static/index.html`,可以設定 `html=True`:
```python
app.mount(
"/static",
StaticFiles(
directory=str(STATIC_DIR),
html=True,
),
name="static",
)
```
此時:
```text
/static/
```
會嘗試讀取:
```text
static/index.html
```
`html=True` 也常用於部署前端 SPA,但若要完整支援前端路由,可能還需要額外處理 fallback。
---
## 4. 使用瀏覽器或 curl 測試
### 使用瀏覽器
開啟:
```text
http://127.0.0.1:8000/static/hello.txt
```
應該會看到:
```text
Hello FastAPI
```
### 使用 curl
```bash
curl -i http://127.0.0.1:8000/static/hello.txt
```
預期結果類似:
```http
HTTP/1.1 200 OK
content-type: text/plain; charset=utf-8
...
Hello FastAPI
```
測試不存在的檔案:
```bash
curl -i http://127.0.0.1:8000/static/not-found.txt
```
應該得到:
```http
HTTP/1.1 404 Not Found
```
---
## 5. 常見問題
### 找不到靜態目錄
不要只依賴目前工作目錄:
```python
StaticFiles(directory="static")
```
若從不同位置啟動程式,可能找不到目錄。較穩定的方式是使用 `Path(__file__)`:
```python
BASE_DIR = Path(__file__).resolve().parent
app.mount(
"/static",
StaticFiles(directory=str(BASE_DIR / "static")),
name="static",
)
```
### URL 寫錯
若掛載路徑是:
```python
app.mount("/static", ...)
```
檔案 URL 必須是:
```text
/static/檔名
```
而不是:
```text
/檔名
```
例如:
```text
/static/hello.txt
```
### 靜態檔案不是 API 路由
掛載靜態目錄後,不需要為每個檔案撰寫:
```python
@app.get("/static/hello.txt")
```
`StaticFiles` 會依照請求路徑自動尋找檔案並回傳適當的 `FileResponse`。
相關學習地圖、教學課程
Python 後端工程、資料庫