django vue3實(shí)現(xiàn)大文件分段續(xù)傳(斷點(diǎn)續(xù)傳)
前端環(huán)境準(zhǔn)備及目錄結(jié)構(gòu):
npm create vue 并取名為big-file-upload-fontend 通過(guò) npm i 安裝以下內(nèi)容 "dependencies": { "axios": "^1.7.9", "element-plus": "^2.9.1", "js-sha256": "^0.11.0", "vue": "^3.5.13" },
main.js中的內(nèi)容
import { createApp } from 'vue' import App from './App.vue' import ElementPlus from 'element-plus' import 'element-plus/dist/index.css' // app.use(ElementPlus) const app = createApp(App) app.use(ElementPlus) app.mount('#app')
App.vue 中的內(nèi)容:
<template> <div class="button"> <el-upload ref="uploadRef" class="upload-demo" :http-request="uploadFile" :show-file-list="false" > <el-button type="primary">點(diǎn)擊上傳文件</el-button> </el-upload> </div> </template> <script setup> import axios from 'axios' import {sha256} from 'js-sha256' const uploadFile = ({file}) => { // 每4MB為一個(gè)小文件 const chunkSize = 4 * 1024 * 1024; // 4MB // 文件總大小 const fileSize = file.size; // 分成了多少個(gè)片段 const chunks = Math.ceil(fileSize / chunkSize); // 保證文件唯一 const sha256Promise = sha256(file.name); // sha256的參數(shù)只接收字符串 // 詢問(wèn)已經(jīng)上傳了幾個(gè)片段 const checkUploadedChunks = () => { return axios.post('http://127.0.0.1:8000/api/check', { sha256Promise: sha256Promise }).then(response => { return response.data; // response.data 就是下邊的 uploadedChunks }); }; return checkUploadedChunks().then(async uploadedChunks => { if (uploadedChunks.length === chunks) { console.log("已經(jīng)上傳完成就不需要再重復(fù)上傳") return Promise.resolve(); } for (let i = 0; i < chunks; i++) { const formData = new FormData(); // 將之前上傳過(guò)的片段過(guò)濾掉,即不上傳之前上傳過(guò)的內(nèi)容 if (uploadedChunks.includes(i + 1)) { continue; } const start = i * chunkSize; // 將文件分片 const chunk = file.slice(start, start + chunkSize); // 使用FormData形式上傳文件 formData.append('chunk', chunk); formData.append('chunkNumber', i + 1); formData.append('chunksTotal', chunks); formData.append('sha256Promise', sha256Promise); formData.append('filename', file.name); // 一次只上傳一個(gè)片段,本次上傳完成后才上傳下一個(gè) const res = await axios.post('http://127.0.0.1:8000/api/upload', formData) } }); }; </script> <style > html, body{ height: 100%; width: 100%; background-color: pink; } </style>
django后端環(huán)境及目錄:
django-admin startproject big_file_upload_backend # 創(chuàng)建一個(gè)big_file_upload_backend項(xiàng)目
python版本:Python 3.11.11
pip 需要安裝:
Django 5.0.6
django-cors-headers 4.6.0 # 用于解決跨域
big_file_upload_backend/settings.py 中的配置如下:
MIDDLEWARE = [ ...... 'django.contrib.sessions.middleware.SessionMiddleware', "corsheaders.middleware.CorsMiddleware", # CorsMiddleware一定要在CommonMiddleware之前 'django.middleware.common.CommonMiddleware', # 'django.middleware.csrf.CsrfViewMiddleware', # 注釋掉這個(gè) 'django.contrib.auth.middleware.AuthenticationMiddleware', ...... ] # 并在文件最后添加上允許所有跨域 CORS_ALLOW_CREDENTIALS = True CORS_ALLOW_ALL_ORIGINS = True CORS_ALLOW_HEADERS = ('*') # 將STATIC_URL = 'statics/' 替換為下邊這三行 STATIC_URL = 'statics/' STATICFILES_DIRS = [ os.path.join(BASE_DIR, "../statics"), ] # 完整的setting設(shè)置如下: """ Django settings for big_file_upload_backend project. Generated by 'django-admin startproject' using Django 4.2. For more information on this file, see https://docs.djangoproject.com/en/4.2/topics/settings/ For the full list of settings and their values, see https://docs.djangoproject.com/en/4.2/ref/settings/ """ import os from pathlib import Path # Build paths inside the project like this: BASE_DIR / 'subdir'. BASE_DIR = Path(__file__).resolve().parent.parent # Quick-start development settings - unsuitable for production # See https://docs.djangoproject.com/en/4.2/howto/deployment/checklist/ # SECURITY WARNING: keep the secret key used in production secret! SECRET_KEY = 'django-insecure-%sa^&p^%m3+m0ex%@y%la0(zzt4y4k3l%0=p#tipx-kz6w*#=d' # SECURITY WARNING: don't run with debug turned on in production! DEBUG = True ALLOWED_HOSTS = [] # Application definition INSTALLED_APPS = [ 'django.contrib.admin', 'django.contrib.auth', 'django.contrib.contenttypes', 'django.contrib.sessions', 'django.contrib.messages', 'django.contrib.staticfiles', ] MIDDLEWARE = [ 'django.middleware.security.SecurityMiddleware', 'django.contrib.sessions.middleware.SessionMiddleware', "corsheaders.middleware.CorsMiddleware", 'django.middleware.common.CommonMiddleware', # 'django.middleware.csrf.CsrfViewMiddleware', 'django.contrib.auth.middleware.AuthenticationMiddleware', 'django.contrib.messages.middleware.MessageMiddleware', 'django.middleware.clickjacking.XFrameOptionsMiddleware', ] ROOT_URLCONF = 'big_file_upload_backend.urls' TEMPLATES = [ { 'BACKEND': 'django.template.backends.django.DjangoTemplates', 'DIRS': [], 'APP_DIRS': True, 'OPTIONS': { 'context_processors': [ 'django.template.context_processors.debug', 'django.template.context_processors.request', 'django.contrib.auth.context_processors.auth', 'django.contrib.messages.context_processors.messages', ], }, }, ] WSGI_APPLICATION = 'big_file_upload_backend.wsgi.application' # Database # https://docs.djangoproject.com/en/4.2/ref/settings/#databases DATABASES = { 'default': { 'ENGINE': 'django.db.backends.sqlite3', 'NAME': BASE_DIR / 'db.sqlite3', } } # Password validation # https://docs.djangoproject.com/en/4.2/ref/settings/#auth-password-validators AUTH_PASSWORD_VALIDATORS = [ { 'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator', }, { 'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator', }, { 'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator', }, { 'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator', }, ] # Internationalization # https://docs.djangoproject.com/en/4.2/topics/i18n/ LANGUAGE_CODE = 'en-us' TIME_ZONE = 'UTC' USE_I18N = True USE_TZ = True # Static files (CSS, JavaScript, Images) # https://docs.djangoproject.com/en/4.2/howto/static-files/ STATIC_URL = 'statics/' STATICFILES_DIRS = [ os.path.join(BASE_DIR, "../statics"), ] # Default primary key field type # https://docs.djangoproject.com/en/4.2/ref/settings/#default-auto-field DEFAULT_AUTO_FIELD = 'django.db.models.BigAutoField' CORS_ALLOW_CREDENTIALS = True CORS_ALLOW_ALL_ORIGINS = True CORS_ALLOW_HEADERS = ('*')
big_file_upload_backend/urls.py中的配置如下:
from django.contrib import admin from django.urls import path from big_file_upload_backend.views import checks, upload urlpatterns = [ path('admin/', admin.site.urls), path('api/check', checks), path('api/upload', upload), ]
big_file_upload_backend/views.py中的配置如下:
import json import os from django.http import JsonResponse from big_file_upload_backend import settings def checks(request): if request.method == "POST": body = json.loads(request.body.decode("utf-8")) filename = body.get("sha256Promise", None) base_path = settings.STATIC_URL+'record_files/'+filename+'.txt' # base_path = '../statics/record_files/'+filename+'.txt' file_is_exits = os.path.exists(base_path) # 判斷文件是否存在,存在則說(shuō)明之前至少上傳過(guò)一次 if file_is_exits: with open(base_path, 'r') as f: check_list = json.loads(f.readline()) else: # 不存在就返回空 check_list = [] return JsonResponse(check_list, safe=False) def upload(request): if request.method == "POST": # 注意這里用的是request.FILES 因?yàn)閏hunk為文件流形式 chunk = request.FILES.get("chunk") # 當(dāng)前的切片編號(hào) chunk_number = request.POST.get("chunkNumber") # 總切片數(shù)量 chunks_total = int(request.POST.get("chunksTotal")) # 文件名唯一標(biāo)識(shí) sha256_promise = request.POST.get("sha256Promise") # 文件名稱 filename = request.POST.get("filename") # base_path = '../statics/upload_files/'+sha256_promise # 這樣寫無(wú)效 base_path = settings.STATIC_URL + "upload_files/" + sha256_promise # 必須這樣寫 # record_path中的txt文件用于記錄已經(jīng)上傳過(guò)的切片 record_path = settings.STATIC_URL + "record_files/" + sha256_promise+'.txt' # 必須這樣寫 os.makedirs(base_path, exist_ok=True) # 后綴名 ext = filename.split(".")[-1] # 小切片的文件名稱 order_file = chunk_number+'.'+ext fname = base_path+"/" + order_file with open(fname, 'wb') as f: for line in chunk: # 將上傳的文件寫入小切片中,等上傳完成后進(jìn)行合并 f.write(line) # 等寫完了才做判斷 chunk_number_int = int(chunk_number) # 將字符串轉(zhuǎn)成int line_list = [int(chunk_number)] # 默認(rèn)先添加一個(gè)切片片段 if os.path.exists(record_path): with open(record_path, 'r') as f: line_data = f.readline() # 讀取已經(jīng)上傳的小切片 if line_data == '': pass else: line_list = json.loads(line_data) # 將字符串形式的數(shù)組轉(zhuǎn)為python數(shù)組 if chunk_number_int not in line_list: line_list.append(chunk_number_int) # 如果當(dāng)前切片號(hào)不在已上傳的數(shù)組中則添加 with open(record_path, 'w') as f: f.write(json.dumps(line_list)) # 將已上傳的片段列表重新寫回記錄文件中 # 合并小切片片段段 if len(line_list) == chunks_total: with open(base_path+"/"+filename, "wb") as f: # 按照升序一個(gè)一個(gè)合并 for num in sorted(line_list): with open(base_path+"/"+str(num)+"."+ext, 'rb') as r: f.write(r.read()) # 讀取完畢將片段刪除,只保留合并后的文件 os.remove(base_path+"/"+str(num)+"."+ext) # 返回沒啥用 check_list = {"chunk_number": chunk_number, "code": 200} return JsonResponse(check_list)
在項(xiàng)目根目錄下要新建一個(gè)statics目錄,且其下邊要有兩個(gè)目錄:
record_files upload_files
最后分別運(yùn)行前后端項(xiàng)目
前端:npm run dev 后端: python manage.py runserver
點(diǎn)擊上傳文件,選擇一個(gè)較大的文件進(jìn)行上傳,可以看到右側(cè)一直再分片上傳,上傳完成后會(huì)在上述兩個(gè)文件中分別多出兩個(gè)文件
如果是上傳過(guò)程中還可以看到upload_files文件下的小分片中的片段產(chǎn)生和合并過(guò)程,也可以在上傳到一半時(shí)隨機(jī)關(guān)閉瀏覽器,下次打開重新上傳,則會(huì)跳過(guò)之前上傳的繼續(xù)進(jìn)行上傳。上傳完成后的效果:
到此這篇關(guān)于django vue3實(shí)現(xiàn)大文件分段續(xù)傳(斷點(diǎn)續(xù)傳)的文章就介紹到這了,更多相關(guān)django 大文件分段續(xù)傳內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
- vue+element+oss實(shí)現(xiàn)前端分片上傳和斷點(diǎn)續(xù)傳
- Vue 大文件上傳和斷點(diǎn)續(xù)傳的實(shí)現(xiàn)
- Vue+Node實(shí)現(xiàn)大文件上傳和斷點(diǎn)續(xù)傳
- vue實(shí)現(xiàn)大文件分片上傳與斷點(diǎn)續(xù)傳到七牛云
- vue?大文件分片上傳(斷點(diǎn)續(xù)傳、并發(fā)上傳、秒傳)
- Vue.js+express利用切片實(shí)現(xiàn)大文件斷點(diǎn)續(xù)傳
- springboot整合vue2-uploader實(shí)現(xiàn)文件分片上傳、秒傳、斷點(diǎn)續(xù)傳功能
- vue中使用webuploader做斷點(diǎn)續(xù)傳實(shí)現(xiàn)文件上傳功能
- vue實(shí)現(xiàn)大文件切片斷點(diǎn)續(xù)傳
- Vue項(xiàng)目中大文件切片上傳實(shí)現(xiàn)秒傳與斷點(diǎn)續(xù)傳的詳細(xì)實(shí)現(xiàn)過(guò)程
相關(guān)文章
Numpy實(shí)現(xiàn)矩陣運(yùn)算及線性代數(shù)應(yīng)用
這篇文章主要介紹了Numpy實(shí)現(xiàn)矩陣運(yùn)算及線性代數(shù)應(yīng)用,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2021-03-03numpy的sum函數(shù)的axis和keepdim參數(shù)詳解
這篇文章主要介紹了numpy的sum函數(shù)的axis和keepdim參數(shù)詳解,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2021-03-03使用pyecharts在jupyter notebook上繪圖
這篇文章主要介紹了使用pyecharts在jupyter notebook上繪圖,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2017-07-07python基于socket實(shí)現(xiàn)網(wǎng)絡(luò)廣播的方法
這篇文章主要介紹了python基于socket實(shí)現(xiàn)網(wǎng)絡(luò)廣播的方法,涉及Python操作socket的相關(guān)技巧,非常具有實(shí)用價(jià)值,需要的朋友可以參考下2015-04-04Keras搭建M2Det目標(biāo)檢測(cè)平臺(tái)示例
這篇文章主要為大家介紹了Keras搭建M2Det目標(biāo)檢測(cè)平臺(tái)實(shí)現(xiàn)的源碼示例,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2022-05-05python Dejavu庫(kù)快速識(shí)別音頻指紋實(shí)例探究
這篇文章主要為大家介紹了python Dejavu庫(kù)快速識(shí)別音頻指紋實(shí)例探究,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2024-01-01Python實(shí)現(xiàn)局域網(wǎng)遠(yuǎn)程控制電腦
這篇文章主要為大家詳細(xì)介紹了如何利用Python編寫一個(gè)工具,可以實(shí)現(xiàn)遠(yuǎn)程控制局域網(wǎng)電腦關(guān)機(jī),重啟,注銷等功能,感興趣的小伙伴可以參考一下2024-12-12使用C語(yǔ)言來(lái)擴(kuò)展Python程序和Zope服務(wù)器的教程
這篇文章主要介紹了使用C語(yǔ)言來(lái)擴(kuò)展Python程序和Zope服務(wù)器的教程,本文來(lái)自于IBM官方網(wǎng)站技術(shù)文檔,需要的朋友可以參考下2015-04-04Python使用稀疏矩陣節(jié)省內(nèi)存實(shí)例
這篇文章主要介紹了Python使用稀疏矩陣節(jié)省內(nèi)存實(shí)例,矩陣中非零元素的個(gè)數(shù)遠(yuǎn)遠(yuǎn)小于矩陣元素的總數(shù),并且非零元素的分布沒有規(guī)律,則稱該矩陣為稀疏矩陣,需要的朋友可以參考下2014-06-06