Files
djangoadmin-wiki/DjangoAdmin_FastAPI_EleVue/zh/volume4/tools/upload.md
T
2026-09-12 23:12:15 +08:00

129 lines
3.8 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 文件上传
:::tip 说明
提供本地文件上传功能,支持图片和通用文件上传,内置扩展名白名单、大小限制、魔术字节校验和路径遍历防护。服务层位于 `src/modules/upload/service.py`,端点位于 `src/api/v1/endpoints/upload.py`。
:::
## 功能概述
文件上传模块提供统一的文件上传接口 `upload_file`,支持图片、文档、压缩包等各类文件,通过 `UPLOAD_ALLOWED_EXTS` 配置控制允许上传的格式。
```
POST /api/v1/upload/uploadFile —— 统一文件上传入口
```
## 配置项
在 `.env` 中配置上传相关参数:
```bash
# 允许上传的文件扩展名(逗号分隔,留空使用内置智能集合)
UPLOAD_ALLOWED_EXTS=.jpg,.png,.gif,.bmp,.pdf,.doc,.docx,.xls,.xlsx,.ppt,.pptx,.zip,.rar
# 单文件大小上限(MB)
UPLOAD_MAX_SIZE_MB=10
# 上传文件存储根目录
FASTAPI_UPLOAD_DIR=E:\upload
# 文件访问域名(Nginx 或本地代理)
FASTAPI_FILE_URL=http://127.0.0.1:8031/api/file
```
:::tip 温馨提示
`UPLOAD_ALLOWED_EXTS` 配置的扩展名会与内置安全集合取交集,确保不会绕过安全校验。留空时回落到内置智能集合。
:::
## 安全机制
上传模块内置多层安全防护:
### 1. 路径遍历防护
```python
def _is_safe_filename(filename: str) -> bool:
"""拒绝包含路径分隔符或 .. 的文件名"""
normalized = os.path.normpath(filename)
if '..' in normalized.split(os.sep):
return False
basename = os.path.basename(normalized)
return basename == normalized or basename == filename
```
### 2. 高危格式黑名单
`.exe`、`.bat`、`.sh`、`.ps1`、`.js`、`.vbs`、`.svg`、`.webp` 等高危格式无论配置如何一律拒绝。
### 3. 魔术字节校验
通过 `verify_file_magic()` 校验文件头部魔术字节,防止伪造扩展名绕过白名单。
### 4. 流式大小校验
```python
async def _read_upload_limited(file, max_size_bytes):
"""流式读取,超过大小上限立即中断,避免整文件读入内存"""
chunks = []
total = 0
while True:
chunk = await file.read(65536)
if not chunk:
break
total += len(chunk)
if total > max_size_bytes:
return None, R.failed(msg=f"文件大小超过限制,最大允许 {UPLOAD_MAX_SIZE_MB}MB")
chunks.append(chunk)
return b''.join(chunks), None
```
## 文件命名规则
上传文件自动重命名,格式为:`年月日时分秒 + 5位随机数 + 扩展名`
```python
def _generate_filename(ext_with_dot):
timestamp = time.strftime('%Y%m%d%H%M%S')
random_num = '%05d' % random.randint(0, 99999)
return f"{timestamp}{random_num}{ext_with_dot}"
```
文件按日期分目录存储:`{UPLOAD_DIR}/{YYYYMMDD}/{文件名}`
## 接口调用
### 上传文件
```
POST /api/v1/upload/uploadFile
Content-Type: multipart/form-data
Authorization: Bearer <token>
参数: file(文件字段)
```
响应示例:
```json
{
"code": 0,
"msg": "上传成功",
"data": {
"originalName": "photo.jpg",
"fileExtension": "jpg",
"fileType": "image/jpeg",
"fileSize": 306995,
"fileName": "2025030614302512345.jpg",
"filePath": "/20250306/2025030614302512345.jpg",
"fileUrl": "http://127.0.0.1:8031/api/file/20250306/2025030614302512345.jpg"
},
"ok": true
}
```
## 前端集成
前端使用 `Upload` 组件上传,上传成功后将返回的 `fileUrl` 存入业务字段。详见 [文件上传联调](/zh/volume4/integration/upload-sync) 章节。
## 总结
文件上传模块通过扩展名白名单、魔术字节校验、流式大小限制、路径遍历防护等多层安全机制,确保上传功能的安全性。文件自动重命名并按日期分目录存储,避免文件名冲突和信息泄露。统一的 `uploadFile` 接口同时支持图片和各类文件上传。