欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

前端大文件上傳與下載(分片上傳)的詳細(xì)過(guò)程

 更新時(shí)間:2022年11月08日 10:33:48   作者:BreenCL  
最近遇見(jiàn)一個(gè)需要上傳超大大文件的需求,所以下面這篇文章主要給大家介紹了關(guān)于前端大文件上傳與下載(分片上傳)的詳細(xì)過(guò)程,文中通過(guò)實(shí)例代碼介紹的非常詳細(xì),需要的朋友可以參考下

一、問(wèn)題

日常業(yè)務(wù)中難免出現(xiàn)前端需要向后端傳輸大型文件的情況,這時(shí)單次的請(qǐng)求不能滿足傳輸大文件的需求,就需要用到分片上傳

業(yè)務(wù)需求為:用戶可以上傳小于20G的鏡像文件,并進(jìn)顯示當(dāng)前上傳進(jìn)度

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

二、解決

解決思路簡(jiǎn)單為前端選擇文件后讀取到文件的基本信息,包括:文件的大小、文件格式等信息,用于前端校驗(yàn),校驗(yàn)完成后將文件進(jìn)行切片并通過(guò)請(qǐng)求輪詢把切片傳遞給后端

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

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

1.第一步選擇文件

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

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

2.校驗(yàn)文件是否符合規(guī)范

這一步可以根據(jù)需求來(lái)進(jìn)行校驗(yàn),這里需要通過(guò)接口校驗(yàn)當(dāng)前服務(wù)器可用的磁盤容量來(lái)判斷是否有足夠的空間用于存放將要上傳的文件

/* 校驗(yàn)上傳鏡像文件是否符合規(guī)范 */
const checkMirrorFile = async (file) => {
    // 校驗(yàn)文件格式是否正確,支持.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('文件格式錯(cuò)誤,僅支持.acow2/.iso/.ovf/.zip/.tar')
        return false
    }
    // 校驗(yàn)文件大小是否滿足
    let fileSize = file.file.size
    //文件大小是否超出20G
    if (fileSize > 20 * 1024 * 1024 * 1024) {
        ElMessage.warning('上傳文件大小不超過(guò)20G')
        return false
    }
    const res = await checkMirrorFileApi()
    if (res.code !== 200) {
        ElMessage.warning('暫時(shí)無(wú)法查看磁盤可用空間,請(qǐng)重試')
        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,轉(zhuǎn)為字節(jié)B
                saveSize = i.free * 1024 * 1024 * 1024
            }
        })
        // 上傳的文件大小沒(méi)有超出磁盤可用空間
        if (fileSize < saveSize) {
            return true
        } else {
            ElMessage.warning('文件大小超出磁盤可用空間容量')
            return false
        }
    } else {
        ElMessage.warning('文件大小超出磁盤可用空間容量')
        return false
    }
}

3.文件切片上傳

  • 校驗(yàn)完成后就可以進(jìn)行文件的切片上傳了,這里用的類似接口輪詢的方式,每次攜帶一個(gè)切片信息給后端,后端接受到切片并返回成功狀態(tài)碼后再進(jìn)行下一次切片的上傳,代碼如下:
  • 當(dāng)然這里后端沒(méi)有過(guò)多的做切片的處理,可以通過(guò)前端使用多線程,或者不等接口響應(yīng)成功就進(jìn)行下一次傳遞切片的過(guò)程進(jìn)行上傳的提速,這里具體怎么實(shí)現(xiàn)看業(yè)務(wù)需求或者怎么配合上傳
/* 文件切片上傳 */
const uploadFile = async (file, shardIndex, createTime, savePath, relativePath, timeMillis) => {
    // 文件名
    let name = file.name
    // 文件大小
    let size = file.size
    // 分片大小
    let shardSize = 1024 * 1024 * 5
    // 分片總數(shù)
    let shardTotal = Math.ceil(size / shardSize)
    if (shardIndex >= shardTotal) {
        isAlive.value = false
        progress.value = 100
        return
    }
    // 文件開(kāi)始結(jié)束的位置
    let start = shardIndex * shardSize
    let end = Math.min(start + shardSize, size)
    // 開(kāi)始切割
    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)
    // 下面這些值是后端組裝切片時(shí)需要的,跟前端關(guān)系不大
    if (createTime) formData.append("createTime", createTime)
    if (savePath) formData.append("savePath", savePath)
    if (shardIndex < shardTotal) {
        // 進(jìn)度條保留兩位小數(shù)展示
        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) {
            // 這里為所有切片上傳成功后進(jìn)行的操作
            ...
        }
        shardIndex++
        uploadFile(file, shardIndex, res.data.createTime, res.data.savePath, res.data.relativePath, res.data.timeMillis)
    }
}

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

4.分片上傳注意點(diǎn)

首先就是需要配置一下Nginx,我這里的每一個(gè)切片文件的大小為5MB,但是上傳第一片的時(shí)候會(huì)報(bào)413的狀態(tài)碼,因?yàn)镹ginx默認(rèn)上傳文件的大小是1M,所以叫運(yùn)維或者后端同學(xué)改一下配置參數(shù),保證文件傳輸時(shí)不會(huì)受到服務(wù)器的限制

5.大文件下載

  • 這里簡(jiǎn)單說(shuō)一下業(yè)務(wù)中遇到的大文件下載,上述鏡像文件上傳之后是支持用戶下載的,所以怎樣處理20G文件的下載也是需要考慮的,我與后端小伙伴嘗試過(guò)通過(guò)range推流的方式來(lái)處理大文件的下載,當(dāng)下載時(shí)除了控制臺(tái)能看到后一直在推流過(guò)來(lái),界面上不會(huì)出現(xiàn)下載進(jìn)度的窗口,而且當(dāng)文件大小超過(guò)2G時(shí)會(huì)出現(xiàn)瀏覽器緩存不足導(dǎo)致推流的中斷,這里沒(méi)有系統(tǒng)研究具體原因
  • 解決方法是后端直接將文件所存的地址返回給我,當(dāng)然也可以通過(guò)Nginx配置訪問(wèn)到文件存儲(chǔ)的位置也可以,前端則通過(guò)創(chuàng)建a標(biāo)簽的方式進(jìn)行下載,這樣可以直接調(diào)用到瀏覽器自帶的下載直接顯示出來(lái)當(dāng)前文件下載的相關(guān)信息:下載進(jìn)度、傳輸?shù)乃俾屎臀募笮?,用戶體驗(yàn)更好,代碼如下:
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)
    // 通過(guò)創(chuàng)建a標(biāo)簽實(shí)現(xiàn)文件下載
    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',
    })
  }
}

總結(jié)

到此這篇關(guān)于前端大文件上傳與下載(分片上傳)的文章就介紹到這了,更多相關(guān)前端大文件上傳下載內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • Element-ui的table中使用fixed后出現(xiàn)行混亂情況的解決

    Element-ui的table中使用fixed后出現(xiàn)行混亂情況的解決

    這篇文章主要介紹了Element-ui的table中使用fixed后出現(xiàn)行混亂情況的解決方案,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2023-10-10
  • vue項(xiàng)目從node8.x升級(jí)到12.x后的問(wèn)題解決

    vue項(xiàng)目從node8.x升級(jí)到12.x后的問(wèn)題解決

    這篇文章主要介紹了vue項(xiàng)目從node8.x升級(jí)到12.x后的問(wèn)題解決,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2019-10-10
  • vue2實(shí)現(xiàn)數(shù)據(jù)請(qǐng)求顯示loading圖

    vue2實(shí)現(xiàn)數(shù)據(jù)請(qǐng)求顯示loading圖

    這篇文章主要為大家詳細(xì)介紹了vue2實(shí)現(xiàn)數(shù)據(jù)請(qǐng)求顯示loading圖,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2017-11-11
  • 詳解Element-ui NavMenu子菜單使用遞歸生成時(shí)使用報(bào)錯(cuò)

    詳解Element-ui NavMenu子菜單使用遞歸生成時(shí)使用報(bào)錯(cuò)

    這篇文章主要介紹了詳解Element-ui NavMenu子菜單使用遞歸生成時(shí)使用報(bào)錯(cuò),文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2021-04-04
  • el-form錯(cuò)誤提示信息手動(dòng)添加和取消的示例代碼

    el-form錯(cuò)誤提示信息手動(dòng)添加和取消的示例代碼

    這篇文章主要介紹了el-form錯(cuò)誤提示信息手動(dòng)添加和取消,本文通過(guò)示例代碼給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2022-08-08
  • 搭建element-ui的Vue前端工程操作實(shí)例

    搭建element-ui的Vue前端工程操作實(shí)例

    下面小編就為大家分享一篇搭建element-ui的Vue前端工程操作實(shí)例,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧
    2018-02-02
  • 初學(xué)vue出現(xiàn)空格警告的原因及其解決方案

    初學(xué)vue出現(xiàn)空格警告的原因及其解決方案

    今天小編就為大家分享一篇初學(xué)vue出現(xiàn)空格警告的原因及其解決方案,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧
    2019-10-10
  • vue-loader中引入模板預(yù)處理器的實(shí)現(xiàn)

    vue-loader中引入模板預(yù)處理器的實(shí)現(xiàn)

    這篇文章主要介紹了vue-loader中引入模板預(yù)處理器的實(shí)現(xiàn),文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2019-09-09
  • vue-router之路由鉤子函數(shù)應(yīng)用小結(jié)

    vue-router之路由鉤子函數(shù)應(yīng)用小結(jié)

    vue-router提供的導(dǎo)航鉤子主要用來(lái)攔截導(dǎo)航,讓它完成跳轉(zhuǎn)或取消,本文主要介紹了vue-router之路由鉤子函數(shù)應(yīng)用小結(jié),具有一定的參考價(jià)值,感興趣的可以了解一下
    2024-01-01
  • vue3+高德地圖只展示指定市、區(qū)行政區(qū)域的地圖以及遮罩反向鏤空其他地區(qū)

    vue3+高德地圖只展示指定市、區(qū)行政區(qū)域的地圖以及遮罩反向鏤空其他地區(qū)

    vue大屏項(xiàng)目開(kāi)發(fā),客戶覺(jué)得地圖上的文字標(biāo)注太多了,要求地圖上只顯示省市等主要城市的標(biāo)注,這篇文章主要給大家介紹了關(guān)于vue3+高德地圖只展示指定市、區(qū)行政區(qū)域的地圖以及遮罩反向鏤空其他地區(qū)的相關(guān)資料,需要的朋友可以參考下
    2024-02-02

最新評(píng)論