You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

大文件上传超时问题咨询(Django+Minio架构)

解决Django+Minio大文件上传超时问题

针对你当前的架构(用户先传Django再内网转存Minio),超时问题主要来自两个环节:用户上传到Django的请求超时,以及Django同步转存Minio时的后台耗时过长。以下是具体解决方案:

1. 调整基础超时配置

Django 端设置

修改settings.py,放宽文件上传的内存限制和临时存储配置:

# 允许上传的最大文件大小(示例:10GB)
FILE_UPLOAD_MAX_MEMORY_SIZE = 10 * 1024 * 1024 * 1024
DATA_UPLOAD_MAX_MEMORY_SIZE = 10 * 1024 * 1024 * 1024

# 指定临时文件存储目录(确保有足够磁盘空间)
FILE_UPLOAD_TEMP_DIR = '/path/to/large-temp-dir'

Web 服务器配置

如果用Nginx作为反向代理,修改站点配置文件:

# 允许客户端上传的最大文件大小
client_max_body_size 10G;

# 延长代理读取/连接超时时间
proxy_read_timeout 300s;
proxy_connect_timeout 300s;
proxy_send_timeout 300s;

如果用Gunicorn作为WSGI服务器,启动时增加超时参数:

gunicorn your_project.wsgi:application --timeout 300 --keep-alive 60

2. 异步转存Minio,避免阻塞用户请求

同步转存Minio会让用户请求一直等待,直接触发超时。改用异步任务处理转存:

用Celery实现异步转存

  1. 安装Celery并配置消息队列(如Redis或RabbitMQ)
  2. 编写异步任务(tasks.py):
from celery import shared_task
from minio import Minio
from django.conf import settings
import os

@shared_task
def upload_to_minio(local_file_path, bucket_name, object_name):
    # 初始化Minio内网客户端
    minio_client = Minio(
        settings.MINIO_INTERNAL_ENDPOINT,
        access_key=settings.MINIO_ACCESS_KEY,
        secret_key=settings.MINIO_SECRET_KEY,
        secure=False  # 内网传输可关闭HTTPS
    )
    # 检查桶是否存在,不存在则创建
    if not minio_client.bucket_exists(bucket_name):
        minio_client.make_bucket(bucket_name)
    # 上传文件到Minio
    minio_client.fput_object(bucket_name, object_name, local_file_path)
    # 清理本地临时文件
    os.remove(local_file_path)
  1. 在视图中调用异步任务,立即返回响应:
from django.http import JsonResponse
from .tasks import upload_to_minio
from django.conf import settings
import os

def upload_file(request):
    if request.method == 'POST' and request.FILES.get('file'):
        uploaded_file = request.FILES['file']
        # 保存到临时目录
        temp_file_path = os.path.join(settings.FILE_UPLOAD_TEMP_DIR, uploaded_file.name)
        with open(temp_file_path, 'wb+') as destination:
            for chunk in uploaded_file.chunks():
                destination.write(chunk)
        # 异步执行转存任务,不阻塞用户请求
        upload_to_minio.delay(temp_file_path, 'your-bucket-name', uploaded_file.name)
        return JsonResponse({'status': 'success', 'message': '文件已提交,后台正在处理'})
    return JsonResponse({'status': 'error'}, status=400)

3. 最优方案:让用户直接上传到Minio(绕过Django中转)

彻底避免Django作为中转的性能瓶颈,让前端直接通过Minio预签名URL上传:

Django生成预签名上传URL

from minio import Minio
from django.conf import settings
from django.http import JsonResponse

def get_presigned_upload_url(request):
    if request.method == 'GET':
        file_name = request.GET.get('file_name')
        bucket_name = 'your-bucket-name'
        minio_client = Minio(
            settings.MINIO_EXTERNAL_ENDPOINT,
            access_key=settings.MINIO_ACCESS_KEY,
            secret_key=settings.MINIO_SECRET_KEY,
            secure=True  # 外网传输建议开启HTTPS
        )
        # 生成有效期1小时的预签名上传URL
        presigned_url = minio_client.presigned_put_object(bucket_name, file_name, expires=3600)
        return JsonResponse({'presigned_url': presigned_url, 'file_name': file_name})
    return JsonResponse({'status': 'error'}, status=400)

前端直接上传到Minio

前端拿到预签名URL后,直接上传文件,无需经过Django:

async function uploadFileToMinio(file) {
    // 先请求Django获取预签名URL
    const urlResp = await fetch(`/get-presigned-url/?file_name=${file.name}`);
    const urlData = await urlResp.json();
    // 直接上传到Minio
    await fetch(urlData.presigned_url, {
        method: 'PUT',
        body: file,
        headers: {'Content-Type': file.type}
    });
    // 上传完成后通知Django记录文件信息
    await fetch('/record-file/', {
        method: 'POST',
        body: JSON.stringify({file_name: urlData.file_name}),
        headers: {'Content-Type': 'application/json'}
    });
}

4. 分块上传(针对超大文件)

如果文件超过10GB,建议用分块上传,每块大小设为50MB-100MB,避免单块上传超时:

  • Minio原生支持分块上传,结合预签名URL实现前端分块上传
  • Django端可处理分块的合并逻辑(或直接由Minio自动合并)

内容的提问来源于stack exchange,提问作者lornejad

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.22 16:27:35