大文件上传服务
一、前端
[webuploader](http://fex.baidu.com/webuploader/ ''webuploader'')
二、后端
django 2.0.0
这里只贴出核心的代码:
前端的:

<!DOCTYPE html><html lang="en"><head> <meta charset="UTF-8"> <title>Title</title> <!--引入CSS--><link rel="stylesheet" type="text/css" href="https://cdn.staticfile.org/webuploader/0.1.1/webuploader.css"><link rel="stylesheet" type="text/css" href="https://cdn.staticfile.org/twitter-bootstrap/4.1.3/css/bootstrap.css"><!--引入JS--><script type="text/javascript" src="https://cdn.staticfile.org/jquery/3.3.1/jquery.js"></script><script type="text/javascript" src="https://cdn.staticfile.org/webuploader/0.1.1/webuploader.js"></script><script type="text/javascript" src="https://cdn.staticfile.org/twitter-bootstrap/4.1.3/js/bootstrap.js"></script></head><body><div id="uploader" class="wu-example"> <!--用来存放文件信息--> <div id="thelist" class="uploader-list"></div> <div class="btns"> <div id="picker">选择文件</div> <button id="ctlBtn" class="btn btn-default">开始上传</button> </div> <div class="progress"> <!-- 进度条 --> <div class="progress-bar progress-bar-striped active" role="progressbar" ></div> </div></div> <script type="text/javascript"> $(document).ready(function() { var task_id = WebUploader.Base.guid(); //产生task_id var uploader = WebUploader.create({ //创建上传控件 swf: 'https://cdn.staticfile.org/webuploader/0.1.1/Uploader.swf', //swf位置,这个可能与flash有关 server: '/resource/files/upload/', //接收每一个分片的服务器地址 pick: '#picker', //填上传按钮的id选择器值 auto: true, //选择文件后,是否自动上传 chunked: true, //是否分片 chunkSize: 10 * 1024 * 1024, //每个分片的大小,这里为10M chunkRetry: 3, //某分片若上传失败,重试次数 threads: 1, //线程数量,考虑到服务器,这里就选了1 duplicate: true, //分片是否自动去重 formData: { //每次上传分片,一起携带的数据 task_id: task_id, }, }); uploader.on('startUpload', function() { //开始上传时,调用该方法 $('.progress-bar').css('width', '0%'); $('.progress-bar').text('0%'); }); uploader.on('uploadProgress', function(file, percentage) { //一个分片上传成功后,调用该方法 $('.progress-bar').css('width', percentage * 100 - 1 + '%'); $('.progress-bar').text(Math.floor(percentage * 100 - 1) + '%'); }); uploader.on('uploadSuccess', function(file) { //整个文件的所有分片都上传成功,调用该方法 //上传的信息(文件唯一标识符,文件名) var data = {'task_id': task_id, 'filename': file.source['name'] }; $.get('/resource/upload/complete/', data); //ajax携带data向该url发请求 $('.progress-bar').css('width', '100%'); $('.progress-bar').text('上传完成'); }); uploader.on('uploadError', function(file) { //上传过程中发生异常,调用该方法 $('.progress-bar').css('width', '100%'); $('.progress-bar').text('上传失败'); }); uploader.on('uploadComplete', function(file) {//上传结束,无论文件最终是否上传成功,该方法都会被调用 $('.progress-bar').removeClass('active progress-bar-striped'); }); }); </script></body></html>

后端的:
路由

path('files/upload/', views.fileupload,name='图片分片上传'), path('upload/complete/', views.fileMerge,name='上传成功合并'),

视图:

@csrf_exemptdef fileupload(request): if request.method == 'POST': upload_file = request.FILES.get('file') task = request.POST.get('task_id') # 获取文件唯一标识符 chunk = request.POST.get('chunk', 0) # 获取该分片在所有分片中的序号 filename = '%s%s' % (task, chunk) # 构成该分片唯一标识符 print("filename=",filename) default_storage.save('./upload/%s' % filename,ContentFile(upload_file.read())) # 保存分片到本地 return render_to_response('upload.html',locals())@csrf_exemptdef fileMerge(request): print(request.GET) task = request.GET.get('task_id') ext = request.GET.get('filename', '') upload_type = request.GET.get('type') if len(ext) == 0 and upload_type: ext = upload_type.split('/')[1] ext = '' if len(ext) == 0 else '.%s' % ext # 构建文件后缀名 chunk = 0 with open('./upload/%s%s' % (task, ext), 'wb') as target_file: # 创建新文件 while True: try: filename = './upload/%s%d' % (task, chunk) source_file = open(filename, 'rb') # 按序打开每个分片 target_file.write(source_file.read()) # 读取分片内容写入新文件 source_file.close() except IOError: break chunk += 1 os.remove(filename) # 删除该分片,节约空间 return render_to_response('upload.html',locals())

效果图: