使用resumable.js+Django大文件上传:分片及文件消失问题排查
排查django-resumable大文件上传问题的实用步骤
我之前也遇到过类似的问题,下面一步步帮你定位和解决这些问题:
一、先确认分片的实际存储位置
你当前的视图把chunks_dir指向了MEDIA_ROOT,但django-resumable并不会直接把分片存在MEDIA_ROOT根目录下——它会自动生成一个基于文件唯一标识(比如hash值)的子目录来存储分片。
你可以做这些验证:
- 先确认
MEDIA_ROOT的绝对路径是否正确:在Django shell里执行from django.conf import settings; print(settings.MEDIA_ROOT),确保路径和你预期的一致。 - 在视图里添加日志,打印实际的分片存储路径:
查看日志里的路径,直接去对应的目录找分片文件。import logging logger = logging.getLogger(__name__) class UserFileUploadView(ResumableUploadView): @property def chunks_dir(self): chunks_dir = getattr(settings, 'MEDIA_ROOT', None) if not chunks_dir: raise ImproperlyConfigured('You must set settings.MEDIA_ROOT') logger.info(f"Chunk storage directory: {chunks_dir}") return chunks_dir def get_chunk_path(self, request): path = super().get_chunk_path(request) logger.info(f"Current chunk will be saved to: {path}") return path - 检查目录权限:确保运行Django的服务器进程(比如gunicorn、uwsgi对应的用户)有读写
MEDIA_ROOT的权限,Linux下可以用chown -R www-data:www-data /your/media/root调整权限。
二、验证分片是否真的上传成功
有时候前端显示上传成功,但后端实际没收到,或者返回了错误状态码:
- 后端日志监控:重写post方法记录每个分片的上传请求:
如果日志里没收到请求,说明前端和后端的请求路径不匹配;如果状态码不是200,说明后端处理出错。def post(self, request, *args, **kwargs): logger.info(f"Received chunk #{request.POST.get('resumableChunkNumber')} for file {request.POST.get('resumableFileName')}") response = super().post(request, *args, **kwargs) logger.info(f"Chunk upload response status: {response.status_code}") return response - 前端事件监听:在resumable.js里添加事件监听,确认前端的上传状态:
对比前后端日志,确认是否真的完成了分片上传。resumable.on('chunkSuccess', function(file, message) { console.log(`Chunk ${file.chunks.length} uploaded successfully`); }); resumable.on('error', function(message, file) { console.error(`Upload error: ${message}`, file); });
三、解决ConnectionAbortedError和重新上传忽略分片的问题
1. 处理ConnectionAbortedError
这个错误是前端取消上传时,后端连接被中断导致的,直接捕获即可避免抛出500错误:
def post(self, request, *args, **kwargs): try: return super().post(request, *args, **kwargs) except ConnectionAbortedError: logger.warning("Connection aborted during chunk upload - ignoring") return HttpResponse(status=204)
2. 修复重新上传忽略分片的问题
这个问题通常是前端没有触发分片检查,或者后端没有正确返回已上传的分片:
- 前端:在重新上传前先调用
check()方法,让resumable.js检查已上传的分片:// 重新上传前执行 resumable.check(); resumable.upload(); - 后端:重写
get_uploaded_chunks方法,验证已上传分片的检测逻辑:
如果日志里显示已上传分片数量为0,说明分片存储路径和检测路径不匹配,回到第一步确认路径。def get_uploaded_chunks(self, request): uploaded_chunks = super().get_uploaded_chunks(request) logger.info(f"Found {len(uploaded_chunks)} uploaded chunks for file {request.POST.get('resumableFileName')}") return uploaded_chunks
四、上传完成后无需刷新即可重新上传
这是因为resumable.js的文件队列没有清空,上传完成后需要手动移除文件或重置实例:
resumable.on('fileSuccess', function(file, message) { // 处理上传成功的业务逻辑 resumable.removeFile(file); // 从队列中移除当前文件 // 如果需要允许再次选择同一个文件,可以重置实例 // resumable = new Resumable({/* 你的配置 */}); });
另外,django-resumable默认不会自动删除分片文件,你可以在合并完成后手动清理:
import shutil from os.path import dirname def post(self, request, *args, **kwargs): response = super().post(request, *args, **kwargs) // 判断是否是最后一个分片,合并完成后清理分片目录 if request.POST.get('resumableChunkNumber') == request.POST.get('resumableTotalChunks'): chunk_path = self.get_chunk_path(request) chunk_dir = dirname(chunk_path) shutil.rmtree(chunk_dir) logger.info(f"Cleaned up chunk directory: {chunk_dir}") return response
内容的提问来源于stack exchange,提问作者Magrias
相关产品推荐
相关产品推荐

