最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

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

 更新時(shí)間:2022年11月08日 10:33:48   作者:BreenCL  
最近遇見一個(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開始的切片
        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
    }
    // 文件開始結(jié)束的位置
    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)
    // 下面這些值是后端組裝切片時(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)文章

  • vue踩坑記之npm?install報(bào)錯(cuò)問(wèn)題解決總結(jié)

    vue踩坑記之npm?install報(bào)錯(cuò)問(wèn)題解決總結(jié)

    當(dāng)你跑起一個(gè)項(xiàng)目的時(shí)候,第一步需要先安裝依賴npm install,下面這篇文章主要給大家介紹了關(guān)于vue踩坑之npm?install報(bào)錯(cuò)問(wèn)題解決的相關(guān)資料,需要的朋友可以參考下
    2022-06-06
  • 一文帶你完全掌握Vue自定義指令

    一文帶你完全掌握Vue自定義指令

    作為使用Vue的開發(fā)者,我們對(duì)Vue指令一定不陌生,諸如v-model、v-on、等,同時(shí)Vue也為開發(fā)者提供了自定義指令的api,熟練的使用自定義指令可以極大的提高了我們編寫代碼的效率,讓我們可以節(jié)省時(shí)間開心的摸魚
    2023-03-03
  • uni-app資源引用的方法匯總(絕對(duì)路徑和相對(duì)路徑)

    uni-app資源引用的方法匯總(絕對(duì)路徑和相對(duì)路徑)

    在基于UniApp開發(fā)跨平臺(tái)應(yīng)用時(shí),開發(fā)者通過(guò)特定語(yǔ)法來(lái)管理和加載應(yīng)用程序的各種資源文件,如圖片、字體、音頻、視頻等,在uni-app中,資源通常會(huì)被組織在項(xiàng)目的各個(gè)目錄下,本文給大家介紹了uni-app資源引用的方法匯總,需要的朋友可以參考下
    2025-01-01
  • vue 監(jiān)聽屏幕高度的實(shí)例

    vue 監(jiān)聽屏幕高度的實(shí)例

    今天小編就為大家分享一篇vue 監(jiān)聽屏幕高度的實(shí)例,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧
    2018-09-09
  • vue2項(xiàng)目解決IE、360瀏覽器兼容問(wèn)題的辦法

    vue2項(xiàng)目解決IE、360瀏覽器兼容問(wèn)題的辦法

    雖然已經(jīng)擯棄ie的使用,但是在現(xiàn)階段還是在某些場(chǎng)景下需要用到ie,這篇文章主要給大家介紹了關(guān)于vue2項(xiàng)目解決IE、360瀏覽器兼容問(wèn)題的辦法,文中通過(guò)代碼介紹的非常詳細(xì),需要的朋友可以參考下
    2024-09-09
  • 尤大大新活petite-vue的實(shí)現(xiàn)

    尤大大新活petite-vue的實(shí)現(xiàn)

    打開尤大大的GitHub,發(fā)現(xiàn)多了個(gè)叫 petite-vue 的東西,Vue3 和 Vite 還沒(méi)學(xué)完呢,又開始整新東西了?本文就來(lái)介紹一下
    2021-07-07
  • 前端Vue項(xiàng)目部署到服務(wù)器的全過(guò)程以及踩坑記錄

    前端Vue項(xiàng)目部署到服務(wù)器的全過(guò)程以及踩坑記錄

    使用Vue做前后端分離項(xiàng)目時(shí),通常前端是單獨(dú)部署,用戶訪問(wèn)的也是前端項(xiàng)目地址,因此前端開發(fā)人員很有必要熟悉一下項(xiàng)目部署的流程,下面這篇文章主要給大家介紹了關(guān)于前端Vue項(xiàng)目部署到服務(wù)器的全過(guò)程以及踩坑記錄的相關(guān)資料,需要的朋友可以參考下
    2023-05-05
  • Vue中組件的數(shù)據(jù)共享分析講解

    Vue中組件的數(shù)據(jù)共享分析講解

    本文章向大家介紹vue組件中的數(shù)據(jù)共享,主要包括vue組件中的數(shù)據(jù)共享使用實(shí)例、應(yīng)用技巧、基本知識(shí)點(diǎn)總結(jié)和需要注意事項(xiàng),具有一定的參考價(jià)值,需要的朋友可以參考一下
    2022-12-12
  • vue2 webpack proxy與nginx配置方式

    vue2 webpack proxy與nginx配置方式

    這篇文章主要介紹了vue2 webpack proxy與nginx配置方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2022-10-10
  • vue-cli3+typescript初體驗(yàn)小結(jié)

    vue-cli3+typescript初體驗(yàn)小結(jié)

    這篇文章主要介紹了vue-cli3+typescript初體驗(yàn)小結(jié),小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧
    2019-02-02

最新評(píng)論

沿河| 逊克县| 湖州市| 兰州市| 仁化县| 咸阳市| 玉门市| 中西区| 东城区| 屏南县| 噶尔县| 苍梧县| 武宁县| 全椒县| 如东县| 凤凰县| 太和县| 乾安县| 湖州市| 汾西县| 沾化县| 青海省| 朝阳区| 鄂伦春自治旗| 泗洪县| 名山县| 黄平县| 洛南县| 定日县| 常熟市| 唐海县| 宁陕县| 嘉善县| 余庆县| 岳西县| 吴旗县| 北票市| 绿春县| 衡东县| 开原市| 林甸县|