# 文件上传完整流程 本章从配置到使用,完整说明文件上传功能的实现方式,包括后端接口、前端组件、安全机制和最佳实践。 ## 上传架构 ``` 前端 Vue3 后端 Django 文件系统 ┌──────────┐ ┌──────────────┐ ┌──────────┐ │ Upload │ multipart │ 安全校验 │ 写入 │ uploads/ │ │ 组件 │ ─────────> │ ─ 扩展名白名单│ ───────> │ temp/ │ │ │ │ ─ MIME 校验 │ │ 日期/ │ │ │ │ ─ 大小校验 │ │ xxx.jpg│ └──────────┘ └──────────────┘ └──────────┘ │ ▼ ┌──────────────┐ │ 返回 fileUrl │ │ 前端存入字段 │ └──────────────┘ ``` ## 环境变量配置 在 `config/env.py` 中配置: | 变量 | 默认值 | 说明 | |:----|:----|:----| | `DJANGO_UPLOAD_DIR` | `{项目根目录}/public/uploads` | 上传文件存储目录 | | `DJANGO_FILE_URL` | `http://file.django.elevue` | 文件访问域名 | | `DJANGO_TEMP_PATH` | `{DJANGO_UPLOAD_DIR}/temp` | 临时文件目录 | ## 上传接口 系统提供统一的文件上传入口,支持图片、文档、压缩包等各类文件: ### 上传文件 ``` POST /upload/uploadFile Content-Type: multipart/form-data Authorization: Bearer file: <文件> ``` 支持格式: ``` 图片:.jpeg, .jpg, .png, .gif, .bmp 文档:.pdf, .doc, .docx, .xls, .xlsx, .ppt, .pptx, .txt ``` 成功响应: ```json { "code": 0, "msg": "上传成功", "data": { "originalName": "photo.jpg", "fileExtension": "jpg", "fileType": "image/jpeg", "fileSize": 306995, "fileName": "2025030614302512345.jpg", "filePath": "/temp/20250306/2025030614302512345.jpg", "fileUrl": "http://file.django.elevue/temp/20250306/2025030614302512345.jpg" }, "ok": true } ``` :::tip 富文本编辑器集成 富文本编辑器(如 WangEditor 等)的图片上传同样使用此接口。编辑器配置上传地址为 `/upload/uploadFile`,上传成功后从 `response.data.fileUrl` 获取图片 URL 即可。 ::: ## 安全机制 ### 扩展名白名单 只允许指定的扩展名格式上传,拒绝危险格式(如 `.exe`、`.bat`、`.sh`、`.js` 等)。 ### MIME 类型校验 通过 `mimetypes` 模块推断文件的 MIME 类型,确保文件内容与扩展名一致。 ### 临时目录隔离 上传的文件首先存储在 `temp` 临时目录,业务数据提交时才迁移到正式目录。未提交的临时文件可定期清理。 ## 文件存储策略 ### 目录结构 ``` public/uploads/ ├── temp/ # 临时文件目录 │ ├── 20260905/ │ │ ├── 2026090514302512345.jpg │ │ └── 2026090515011278901.pdf │ └── 20260906/ ├── example/ # 正式文件目录(按业务分类) │ ├── 20260905/ │ │ └── 2026090514302512345.jpg │ └── 20260906/ └── article/ └── 20260906/ ``` - 按日期分目录存储(`{日期}/`),避免单目录文件过多 - 文件名使用 `年月日时分秒 + 5位随机数` 重命名,避免中文文件名和冲突 - 保留原始扩展名 ### 文件访问 URL 上传成功后返回的 `fileUrl` 是拼接了 `DJANGO_FILE_URL` 前缀的完整 URL: ``` http://file.django.elevue/temp/20250306/2025030614302512345.jpg ``` Service 层的 `get_file_url()` 会自动为文件字段补此前缀。 ## 前端集成 ### 文件上传组件 ```vue ``` ## 业务模块中的文件字段 在 Service 中使用 `save_file()` 处理文件迁移: ```python # application/example/services.py from utils.common import save_file, get_file_url def add_example(request): data, error = parse_request_body(request) # ... avatar = cleaned_data.get('avatar') if avatar: avatar = save_file(avatar, "example") # 迁移到正式目录 Example.objects.create(avatar=avatar, ...) ``` ### 自动处理逻辑 1. **新增/更新时**:检测文件字段值是否为临时路径,如果是则迁移到正式目录 2. **列表/详情时**:通过 `get_file_url()` 自动为文件字段补全 `DJANGO_FILE_URL` 前缀 ## 富文本中的图片 使用 `save_content()` 处理富文本中的图片: ```python # utils/common.py def save_content(content, title, directory): """提取富文本中的图片并迁移,替换 URL""" image_urls = re.findall('img src="(.*?)"', content, re.S) for url in image_urls: image = save_file(url, directory) if image: content = content.replace(url, "[IMG_URL]" + image) return content ``` ## 常见问题 ### 上传报演示环境无权限 **原因**:演示模式下写操作被拦截。 **解决**:将 `.env` 中的 `DJANGO_DEMO` 设为 `False`。 ### 图片上传成功但不显示 **原因**:`DJANGO_FILE_URL` 配置错误或前端未拼接域名。 **解决**:检查 `config/env.py` 中的 `DJANGO_FILE_URL` 配置,确保前端正确拼接。 ## 总结 文件上传功能通过扩展名白名单 + MIME 类型校验 + 临时目录隔离等安全机制保障安全性。文件按日期分目录存储,使用时间戳 + 随机数重命名。统一的 `uploadFile` 接口支持图片和各类文件上传。Service 层通过 `save_file()` 和 `save_content()` 处理文件迁移和 URL 拼接。