中文字幕av专区_日韩电影在线播放_精品国产精品久久一区免费式_av在线免费观看网站

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

web前端大文件上傳與下載問題怎么解決

發布時間:2022-11-09 09:26:58 來源:億速云 閱讀:232 作者:iii 欄目:開發技術

這篇文章主要介紹了web前端大文件上傳與下載問題怎么解決的相關知識,內容詳細易懂,操作簡單快捷,具有一定借鑒價值,相信大家閱讀完這篇web前端大文件上傳與下載問題怎么解決文章都會有所收獲,下面我們一起來看看吧。

    一、問題

    日常業務中難免出現前端需要向后端傳輸大型文件的情況,這時單次的請求不能滿足傳輸大文件的需求,就需要用到分片上傳

    業務需求為:用戶可以上傳小于20G的鏡像文件,并進顯示當前上傳進度

    前端:vue3.x+Element Plus組件+axios

    二、解決

    解決思路簡單為前端選擇文件后讀取到文件的基本信息,包括:文件的大小、文件格式等信息,用于前端校驗,校驗完成后將文件進行切片并通過請求輪詢把切片傳遞給后端

    Vue的元素代碼如下,主要借助el-upload組件:

    <template>
        ...
        <!-- 文件上傳 -->
        <el-upload
                   :show-file-list="false"
                   action
                   class="mirror-upload"
                   :http-request="putinMirror"
                   >
            <button>上傳環境鏡像</button>
        </el-upload>
        ...
        <!-- 進度顯示 -->
         <el-progress
                      :percentage="progress"
                      :indeterminate="true"
                      />
        ...
    </template>
    <script setup>
        // 引入封裝好的接口api,根據提供的接口文檔自行封裝即可
        import {
            // 普通get請求api
            checkMirrorFileApi,
            // 普通post請求api
            uploadShardFileApi,
        } from "@/assets/api/uploadApi.js"
        import { ref } from 'vue'
        // 文件輸進度條
        const progress = ref(0)
        ...
    </script>

    1.第一步選擇文件

    配合組件選取需要上傳的文件

    /* 上傳環境鏡像 分片上傳 */
    const putinMirror = async (file) => {
        // 校驗文件是否符合規范(注意這里的異步方法,因為調用了接口加上await,校驗函數若不調用接口可以不寫await,否則返回promise對象)
        if (await checkMirrorFile(file)) {
            // 文件相關信息
            let files = file.file
            // 從0開始的切片
            let shardIndex = 0
            // 調用切片方法
            uploadFile(files, shardIndex)
        }
    }

    2.校驗文件是否符合規范

    這一步可以根據需求來進行校驗,這里需要通過接口校驗當前服務器可用的磁盤容量來判斷是否有足夠的空間用于存放將要上傳的文件

    /* 校驗上傳鏡像文件是否符合規范 */
    const checkMirrorFile = async (file) => {
        // 校驗文件格式是否正確,支持.acow2/.iso/.ovf/.zip/.tar
        let fileType = file.file.name.split('.')
        if (fileType[fileType.length - 1] !== 'acow2' && fileType[fileType.length - 1] !== 'iso' && fileType[fileType.length - 1] !== 'ovf' && fileType[fileType.length - 1] !== 'zip' && fileType[fileType.length - 1] !== 'tar') {
            ElMessage.warning('文件格式錯誤,僅支持.acow2/.iso/.ovf/.zip/.tar')
            return false
        }
        // 校驗文件大小是否滿足
        let fileSize = file.file.size
        //文件大小是否超出20G
        if (fileSize > 20 * 1024 * 1024 * 1024) {
            ElMessage.warning('上傳文件大小不超過20G')
            return false
        }
        const res = await checkMirrorFileApi()
        if (res.code !== 200) {
            ElMessage.warning('暫時無法查看磁盤可用空間,請重試')
            return false
        }
        // 查看磁盤容量大小
        if (res.data.diskDevInfos && res.data.diskDevInfos.length > 0) {
            let saveSize = 0
            res.data.diskDevInfos.forEach(i => {
                // 磁盤空間賦值
                if (i.devName === '/dev/mapper/centos-root') {
                    // 返回值為GB,轉為字節B
                    saveSize = i.free * 1024 * 1024 * 1024
                }
            })
            // 上傳的文件大小沒有超出磁盤可用空間
            if (fileSize < saveSize) {
                return true
            } else {
                ElMessage.warning('文件大小超出磁盤可用空間容量')
                return false
            }
        } else {
            ElMessage.warning('文件大小超出磁盤可用空間容量')
            return false
        }
    }

    3.文件切片上傳

    • 校驗完成后就可以進行文件的切片上傳了,這里用的類似接口輪詢的方式,每次攜帶一個切片信息給后端,后端接受到切片并返回成功狀態碼后再進行下一次切片的上傳,代碼如下:

    • 當然這里后端沒有過多的做切片的處理,可以通過前端使用多線程,或者不等接口響應成功就進行下一次傳遞切片的過程進行上傳的提速,這里具體怎么實現看業務需求或者怎么配合上傳

    /* 文件切片上傳 */
    const uploadFile = async (file, shardIndex, createTime, savePath, relativePath, timeMillis) => {
        // 文件名
        let name = file.name
        // 文件大小
        let size = file.size
        // 分片大小
        let shardSize = 1024 * 1024 * 5
        // 分片總數
        let shardTotal = Math.ceil(size / shardSize)
        if (shardIndex >= shardTotal) {
            isAlive.value = false
            progress.value = 100
            return
        }
        // 文件開始結束的位置
        let start = shardIndex * shardSize
        let end = Math.min(start + shardSize, size)
        // 開始切割
        let packet = file.slice(start, end)
        let formData = new FormData()
        formData.append("file", packet)
        formData.append("fileName", name)
        formData.append("size", size)
        formData.append("shardIndex", shardIndex)
        formData.append("shardSize", shardSize)
        formData.append("shardTotal", shardTotal)
        // 下面這些值是后端組裝切片時需要的,跟前端關系不大
        if (createTime) formData.append("createTime", createTime)
        if (savePath) formData.append("savePath", savePath)
        if (shardIndex < shardTotal) {
            // 進度條保留兩位小數展示
            progress.value = ((shardIndex / shardTotal) * 100).toFixed(2) * 1
            const res = await uploadShardFileApi(formData)
            if (res.code !== 200) {
                ElMessage.error(res.msg)
                progress.value = 0
                return
            }
            if (res.msg == '上傳成功' && res.data.fileName && res.data.filePath) {
                // 這里為所有切片上傳成功后進行的操作
                ...
            }
            shardIndex++
            uploadFile(file, shardIndex, res.data.createTime, res.data.savePath, res.data.relativePath, res.data.timeMillis)
        }
    }

    最后將1、2、3中的代碼合起來就是完整的分片上傳了(前端帶有文件校驗)

    4.分片上傳注意點

    首先就是需要配置一下Nginx,我這里的每一個切片文件的大小為5MB,但是上傳第一片的時候會報413的狀態碼,因為Nginx默認上傳文件的大小是1M,所以叫運維或者后端同學改一下配置參數,保證文件傳輸時不會受到服務器的限制

    5.大文件下載

    • 這里簡單說一下業務中遇到的大文件下載,上述鏡像文件上傳之后是支持用戶下載的,所以怎樣處理20G文件的下載也是需要考慮的,我與后端小伙伴嘗試過通過range推流的方式來處理大文件的下載,當下載時除了控制臺能看到后一直在推流過來,界面上不會出現下載進度的窗口,而且當文件大小超過2G時會出現瀏覽器緩存不足導致推流的中斷,這里沒有系統研究具體原因

    • 解決方法是后端直接將文件所存的地址返回給我,當然也可以通過Nginx配置訪問到文件存儲的位置也可以,前端則通過創建a標簽的方式進行下載,這樣可以直接調用到瀏覽器自帶的下載直接顯示出來當前文件下載的相關信息:下載進度、傳輸的速率和文件大小,用戶體驗更好,代碼如下:

    const downloadMirror = async (item) => {
      let t = {
        id: item.id,
      }
      const res = await downloadMirrorApi(t)
      if (res.headers["content-disposition"]) {
        let temp = res.headers["content-disposition"].split(";")[1].split("filename=")[1]
        let fileName = decodeURIComponent(temp)
        // 通過創建a標簽實現文件下載
        let link = document.createElement('a')
        link.download = fileName
        link.style.display = 'none'
        link.href = res.data.msg
        document.body.appendChild(link)
        link.click()
        document.body.removeChild(link)
      } else {
        ElMessage({
          message: '該文件不存在',
          type: 'warning',
        })
      }
    }

    關于“web前端大文件上傳與下載問題怎么解決”這篇文章的內容就介紹到這里,感謝各位的閱讀!相信大家對“web前端大文件上傳與下載問題怎么解決”知識都有一定的了解,大家如果還想學習更多知識,歡迎關注億速云行業資訊頻道。

    向AI問一下細節

    免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

    AI

    德阳市| 隆林| 通许县| 图木舒克市| 邳州市| 遂昌县| 德安县| 木兰县| 台北县| 会同县| 合肥市| 宜宾县| 太仆寺旗| 延吉市| 莱西市| 大同县| 北海市| 嘉善县| 长沙县| 乌兰县| 东平县| 防城港市| 高平市| 唐河县| 荥经县| 延安市| 海兴县| 通榆县| 金山区| 灌南县| 吉林市| 长宁区| 张家口市| 奇台县| 中山市| 潼南县| 恩施市| 海盐县| 云和县| 略阳县| 霍邱县|