Skip to content

文件上传完整流程

本章从配置到使用,完整说明文件上传功能的实现方式,包括后端接口、前端组件、安全机制和最佳实践。

上传架构

前端 Vue3                后端 Django               文件系统
┌──────────┐            ┌──────────────┐          ┌──────────┐
│ Upload   │  multipart │  安全校验     │  写入    │ uploads/ │
│ 组件     │ ─────────> │  ─ 扩展名白名单│ ───────> │  temp/   │
│          │            │  ─ MIME 校验  │          │   日期/  │
│          │            │  ─ 大小校验   │          │   xxx.jpg│
└──────────┘            └──────────────┘          └──────────┘


                        ┌──────────────┐
                        │ 返回 fileUrl │
                        │ 前端存入字段  │
                        └──────────────┘

环境变量配置

config/env.py 中配置:

变量默认值说明
DJANGO_UPLOAD_DIR{项目根目录}/public/uploads上传文件存储目录
DJANGO_FILE_URLhttp://file.django.elevue文件访问域名
DJANGO_TEMP_PATH{DJANGO_UPLOAD_DIR}/temp临时文件目录

上传接口

系统提供统一的文件上传入口,支持图片、文档、压缩包等各类文件:

上传文件

POST /upload/uploadFile
Content-Type: multipart/form-data
Authorization: Bearer <token>

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
}

富文本编辑器集成

富文本编辑器(如 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
<template>
  <el-upload
    :action="uploadUrl"
    :headers="headers"
    :on-success="handleSuccess"
    :before-upload="beforeUpload"
  >
    <el-button type="primary">上传文件</el-button>
  </el-upload>
</template>

<script setup>
import { ref } from 'vue';
import { useUserStore } from '@/store/modules/user';

const uploadUrl = '/api/upload/uploadFile';
const userStore = useUserStore();
const headers = {
    Authorization: `Bearer ${userStore.token}`,
};

function beforeUpload(file) {
    const isLt10M = file.size / 1024 / 1024 < 10;
    if (!isLt10M) {
        ElMessage.error('文件大小不能超过 10MB');
    }
    return isLt10M;
}

function handleSuccess(response) {
    if (response.code === 0) {
        // 保存 fileUrl 到业务字段
        form.value.cover = response.data.fileUrl;
    }
}
</script>

业务模块中的文件字段

在 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 拼接。

小蚂蚁云团队 · 提供技术支持