UploadFile
===
###### tags: `Python / FastAPI`
###### tags: `Python`, `PyPi`, `backend`, `fastapi`, `UploadFile`, `表單`, `form`
<br>
[TOC]
<br>
## 討論
### FastAPI 檔案上傳錯誤說明與修正
- ### Question
關於 Python FastAPI
```python
@router.post('/upload')
async def upload_file(file):
print('upload: ', file)
```
```
$ curl -X POST http://localhost:8080/client/upload -F "file=@20250401-packages.zip"
{"detail":[{"type":"missing","loc":["query","file"],"msg":"Field required","input":null}]}
```
哪裡出問題?
- ### gpt-4o (2025/04/16)
### ❌ 錯誤訊息
當使用以下 FastAPI 程式碼:
```python
@router.post('/upload')
async def upload_file(file):
print('upload: ', file)
```
搭配這個 `curl` 指令:
```bash
curl -X POST http://localhost:8080/client/upload -F "file=@20250401-packages.zip"
```
會出現以下錯誤:
```
{"detail":[{"type":"missing","loc":["query","file"],"msg":"Field required","input":null}]}
```
### 📌 問題說明
FastAPI 預設會將參數 `file` 解讀為 **Query Parameter**,但你實際上是透過 `multipart/form-data` 上傳檔案。
若沒有使用 `UploadFile` 和 `File(...)` 來明確宣告這是檔案,FastAPI 就不會從表單中解析檔案上傳內容。
---
### ✅ 正確做法:使用 `UploadFile` + `File(...)`
請修改你的 API 為:
```python
from fastapi import APIRouter, UploadFile, File
router = APIRouter()
@router.post('/upload')
async def upload_file(file: UploadFile = File(...)):
print('upload:', file.filename)
return {"filename": file.filename}
```
這樣 FastAPI 才會從表單欄位中解析上傳的檔案。
---
### ✅ 附加需求(可選)
如果你還要額外上傳欄位,例如 `token`:
```python
from fastapi import Form
@router.post('/upload')
async def upload_file(
file: UploadFile = File(...),
token: str = Form(...)
):
...
```
對應的 `curl`:
```
curl -X POST http://localhost:8080/client/upload \
-F "file=@20250401-packages.zip" \
-F "token=abc123"
```
---
### 🔧 延伸功能建議
你可以進一步擴充功能,如下:
- ✅ 檔案上傳解壓縮
- ✅ 上傳後自動觸發後端流程
- ✅ Token 自動產生與驗證
- ✅ 支援多用戶、多組 Token 與權限
- ✅ Swagger UI 支援測試
- ✅ 解壓縮後回傳檔案清單
如需,我可以幫你模組化實作完整專案架構。
<br>
### RuntimeError: Form data requires "python-multipart" to be installed.
- ### Question
RuntimeError: Form data requires "python-multipart" to be installed.
You can install "python-multipart" with:
pip install python-multipart
- ### gpt-4o (2025/04/16)
> FastAPI 檔案上傳錯誤與解法
### 錯誤訊息
當你在 FastAPI 中使用 `UploadFile` 或 `Form` 接收 multipart/form-data 時,若出現以下錯誤:
```
RuntimeError: Form data requires "python-multipart" to be installed. You can install "python-multipart" with:
pip install python-multipart
```
表示你尚未安裝處理表單上傳所需的依賴套件。
---
### ✅ 解法
請安裝 `python-multipart`:
```
pip install python-multipart
```
這個套件會讓 FastAPI 能解析上傳表單,特別是 `UploadFile` 和 `Form(...)` 所需的 `multipart/form-data` 格式。
---
### 📦 建議 dependencies
若你正在開發 FastAPI 專案,建議將以下內容加入 `requirements.txt` 或安裝:
```
fastapi
uvicorn
python-multipart
```
你也可以一鍵安裝全部推薦套件:
```
pip install "fastapi[all]"
```
這樣會連 `python-multipart`、`jinja2`、`pydantic-settings` 等都一併裝好。
---
### ✅ 正確的上傳路由範例
```python=
from fastapi import APIRouter, UploadFile, File
router = APIRouter()
@router.post('/upload')
async def upload_file(file: UploadFile = File(...)):
print('upload:', file.filename)
return {"filename": file.filename}
```
---
### ✅ 對應的 curl 測試指令
```
curl -X POST http://localhost:8080/client/upload -F "file=@20250401-packages.zip"
```
---
有了這些設定後,FastAPI 就能正確處理 `multipart/form-data` 檔案上傳。
---
### 🔧 延伸功能(可選):
你也可以加入以下功能來擴充你的 API:
- ✅ Token 驗證
- ✅ 上傳後自動解壓縮 ZIP
- ✅ 回傳檔案列表
- ✅ Swagger UI 自動化說明文件
- ✅ 多使用者權限控管與 Token 過期機制
如需範例,我可以提供分模組結構的專案範本。
<br>
### 📦 FastAPI 中的 `File(...)` 與 `...` 的意思
- ### gpt-4o (2025/04/16)
### 🔍 `File(...)` 是什麼?
在 FastAPI 中,我們用 `File(...)` 來處理從 `multipart/form-data` 上傳的檔案。
範例:
```python
from fastapi import File, UploadFile
async def upload_file(file: UploadFile = File(...)):
...
```
這樣的寫法會讓 FastAPI 知道:
- `file` 是從上傳表單來的檔案。
- 使用者 **必須提供這個檔案**,否則會報錯。
---
### ✅ `...` 是什麼?
`...` 是 Python 的內建物件,名稱是 `Ellipsis`,在 FastAPI / Pydantic 中有特別用途:
- `...` 表示「這個欄位是 **必填** 的」。
- 等同於告訴 FastAPI:「這個欄位沒有預設值,也不能省略」。
範例比較:
```
# 必填
file: UploadFile = File(...)
# 選填(預設為 None)
file: UploadFile = File(None)
```
---
### 📥 FastAPI 接收不同資料來源對照表
| FastAPI 類型 | 資料來源 | 寫法範例 | 說明 |
|--------------|----------------------|------------------------|------------------------------|
| `Query(...)` | URL 查詢字串 | `?id=123` | 來自網址後方的參數 |
| `Form(...)` | 表單欄位(非檔案) | `application/x-www-form-urlencoded` 或 `multipart/form-data` | 接收一般表單欄位 |
| `File(...)` | 上傳檔案(表單檔案) | `multipart/form-data` | 專門處理檔案上傳 |
| `Body(...)` | JSON 請求主體 | `application/json` | 接收 JSON 結構資料 |
---
### 🚨 常見錯誤
如果你這樣寫:
```python
async def upload_file(file):
...
```
FastAPI 會預設你是從 `query` 接收 `file`,而不是從表單上傳,導致出現錯誤訊息:
```json
{"detail":[{"type":"missing","loc":["query","file"],"msg":"Field required","input":null}]}
```
---
### ✅ 解法總結
- 要處理上傳檔案:使用 `file: UploadFile = File(...)`
- `...` 表示這是 **必填欄位**
- 要記得安裝必要套件:
```bash
pip install python-multipart
```
---
是否也需要我幫你補上 `Form(...)` 的對應範例一起整理?
<br>
{%hackmd vaaMgNRPS4KGJDSFG0ZE0w %}