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

前端文件上傳實現(xiàn)代碼示例(文件上傳,分片上傳,斷點續(xù)傳)

 更新時間:2024年09月28日 11:07:32   作者:STATICHIT靜砸  
本文總結(jié)了普通文件上傳和分片上傳的方法,普通上傳通過FormData和axios實現(xiàn)文件發(fā)送,而分片上傳則將大文件切割并并行或串行上傳,最后合并分片,提高上傳效率和穩(wěn)定性,還介紹了斷點續(xù)傳和處理上傳過程中的異常情況,需要的朋友可以參考下

普通文件上傳

思路:

首先獲取用戶選擇的文件對象,并將其添加到一個 FormData 對象中。然后,使用 axios 的 post 方法將 FormData 對象發(fā)送到服務(wù)器。在 then 和 catch 中,我們分別處理上傳成功和失敗的情況,并輸出相應(yīng)的信息。

需要注意,在使用 axios 進行文件上傳時,必須將數(shù)據(jù)格式設(shè)置為 multipart/form-data,否則文件對象將無法正確傳輸。

傳統(tǒng)方式:

function handleFileSelect(e) {
    const formData = new FormData();
    formData.append("file", file);
    const header={"Content-Type": "multipart/form-data;charset=UTF-8"};
    axios.post("http://xxx.xxx.xx.x:xxxx/upload",formData,{
       headers: header,
    }).then((res) => {
       console.log(res);
    });
}

封裝方法:

在大型項目中,我一般會把get,post,put,delete以及upload方法進行封裝。

//封裝upload方法
import axios from "axios";
const requests = axios.create({
  //配置對象
  baseURL: myBaseURL,
  timeout: 10000,
});
const header = {
  "Content-Type": "multipart/form-data;charset=UTF-8",
};
const http = {
  upload(url="",formData){
    return new Promise((resolve, reject) => {
      requests({
        url,
        data: formData,
        headers: header,
        method: "POST",
      })
        .then((res) => {
          resolve(res.data);
          return res;
        })
        .catch((err) => {
          reject(err);
        });
    });
  },
....
}
//封裝請求方法
apiFun.upload = (formData) => {
  return http.upload("/user/headshot", formData);
};
//上傳文件
function handleFileSelect(e) {
    const formData = new FormData();
    formData.append("file", file);
    ApiFun.upload(formData).then((res) => {
      console.log(res);
      ElMessage.success("上傳成功");
    });
  }
}

分片上傳

分片上傳是將一個大文件切分成多個小塊,然后將這些小塊逐個上傳到服務(wù)器的一種上傳方式。

思路:

簡單來說就是三個步驟:分片=》并行/串行發(fā)送分片=》合并請求

 為什么要做分片上傳?通常大家第一會想到的就是因為文件太大了。

分片上傳解決以下幾個問題:

1. 大文件上傳容易導(dǎo)致網(wǎng)絡(luò)傳輸中斷:當(dāng)我們嘗試上傳一個大文件時,如果網(wǎng)絡(luò)連接不穩(wěn)定或上傳過程中出現(xiàn)異常,整個文件都需要重新上傳。而通過分片上傳,即使某個小塊上傳失敗,只需要重新上傳該小塊,而不必重新上傳整個文件。

2. 降低服務(wù)器壓力:如果直接上傳一個大文件,服務(wù)器需要同時處理大量的數(shù)據(jù),并且需要分配較大的內(nèi)存空間來存儲這些數(shù)據(jù)。而通過分片上傳,可以將服務(wù)器的負(fù)載分散到多個小塊的處理上,減輕了服務(wù)器的壓力。

3. 提高上傳速度和穩(wěn)定性:將大文件切分成小塊后,可以并行上傳這些小塊,從而提高上傳速度。同時,如果某個小塊上傳失敗,可以重試該小塊,而不會影響其他小塊的上傳,從而提高上傳的穩(wěn)定性。

4. 支持?jǐn)帱c續(xù)傳:通過分片上傳,服務(wù)器可以保存每個小塊的上傳狀態(tài),包括已上傳的字節(jié)數(shù)和已確認(rèn)的小塊。如果上傳過程中斷,下次可以從上次中斷的位置繼續(xù)上傳,實現(xiàn)斷點續(xù)傳的功能。

具體實現(xiàn)思路:

  • 將大文件轉(zhuǎn)換成二進制流的格式
  • 利用流可以切割的屬性,將二進制流切割成多份
  • 組裝和分割塊同等數(shù)量的請求塊(或同等大小的請求塊),并行或串行的形式發(fā)出請求
  • 待我們監(jiān)聽到所有請求都成功發(fā)出去以后,再給服務(wù)端發(fā)出一個合并的信號

 一般我會選擇在文件小于5MB時普通文件上傳,當(dāng)文件大于5MB時進行分片上傳。

整體邏輯就是:

將大文件進行分片

我這里封裝了md5計算方法

'use strict';
import '../plugins/js-spark-md5.js'

export default function (file, callback) {
  var blobSlice = File.prototype.slice || File.prototype.mozSlice || File.prototype.webkitSlice,
    file = file,
    chunkSize = 4194304,                             // Read in chunks of 4MB 即 4 * 1024 * 1024
    chunks = Math.ceil(file.size / chunkSize),
    currentChunk = 0,
    spark = new SparkMD5.ArrayBuffer(),              //向上取整,因為最后一塊不一定滿4MB
    fileReader = new FileReader();

  fileReader.onload = function (e) {
    console.log('read chunk nr', currentChunk + 1, 'of', chunks);
    spark.append(e.target.result);                   // Append array buffer
    currentChunk++;

    if (currentChunk < chunks) {
      loadNext();
    } else {
      let data = {
        "etag": spark.end(),
        "chunks": chunks,
        "size": file.size,
        "blockToken": "",
      }
      callback(null, data);
      console.log('finished loading');
    }
  };

  fileReader.onerror = function () {
    callback('oops, something went wrong.');
  };

  function loadNext() {
    var start = currentChunk * chunkSize,
      end = ((start + chunkSize) >= file.size) ? file.size : start + chunkSize;

    fileReader.readAsArrayBuffer(blobSlice.call(file, start, end));
  }

  loadNext();
};

 因為我實現(xiàn)了多文件并行分片上傳,所以這里在將文件加入列表時我就已經(jīng)計算好了相關(guān)屬性

當(dāng)md5計算完畢,文件顯示準(zhǔn)備就緒。

創(chuàng)建切片請求:

返回結(jié)果的屬性之一exist反應(yīng)該文件是否上傳過,如果存在,則可以實現(xiàn)秒傳,無需再次上傳。

如果不存在,則獲取此次上傳的目標(biāo)ip和端口號

將每一個切片 并行/串行 的方式發(fā)出:

我這里使用promise實現(xiàn)了并行(如果是用循環(huán)遍歷切片串行傳輸,可以通過循環(huán)下標(biāo)i的值與切片總數(shù)相等來判斷分片是否上傳完畢)

且每個分片是大小一致的。

當(dāng)所有分片上傳完成后。再給服務(wù)器端發(fā)送合并請求。

文件合并請求:

斷點續(xù)傳

在分片上傳的基礎(chǔ)上,我們很容易考慮到斷點續(xù)傳的需求。

思路:

點擊暫停按鈕時停止上傳。點擊繼續(xù)上傳,繼續(xù)上傳剩下的分片或請求。

我們很容易想到給每個分片一個是否上傳的狀態(tài)標(biāo)識來識別該分片是否上傳完成。

法1:初始時所有分片的狀態(tài)為未上傳,當(dāng)一個分片上傳完成,將該標(biāo)識設(shè)置為已上傳。暫停上傳時,將當(dāng)前上傳的分片也設(shè)置為未上傳;重新進行上傳時,就可以繼續(xù)把其他未上傳的分片上傳了。

法2:將所有分片加入一個列表中,每當(dāng)成功上傳一個分片,就將該分片從列表中刪除。而列表中剩下的分片就是還未上傳的分片。

秒傳

即前面分片上傳中提到的。發(fā)送創(chuàng)建分片請求時,讓服務(wù)器檢查該文件是否上傳過,如果是,則無需重復(fù)上傳,直接顯示上傳成功實現(xiàn)秒傳功能。

其他問題 之 上傳過程中刷新頁面怎么辦

如果在上傳過程中刷新了頁面,通常會導(dǎo)致上傳任務(wù)中斷。

因為刷新頁面會導(dǎo)致瀏覽器重新加載頁面,之前的 JavaScript 代碼和網(wǎng)絡(luò)請求都會被取消。

當(dāng)頁面刷新后,可以嘗試使用以下方法來處理上傳任務(wù)的中斷情況:

1. 利用瀏覽器的緩存機制:在上傳之前,將文件對象保存到瀏覽器的本地存儲或會話存儲中。當(dāng)頁面刷新后,通過讀取緩存中的文件對象信息,重新構(gòu)建上傳任務(wù),并恢復(fù)之前的上傳進度。

2. 檢測頁面刷新事件:可以通過監(jiān)聽 `beforeunload` 事件來捕獲頁面刷新的操作。在該事件觸發(fā)時,可以彈出一個確認(rèn)框,提示用戶是否繼續(xù)離開頁面。如果用戶選擇離開頁面,可以先中止當(dāng)前的上傳請求,然后再進行頁面刷新。

該方法并不能完全保證上傳任務(wù)的連續(xù)性和完整性。在實際應(yīng)用中,為了確保上傳任務(wù)的可靠性,通常建議在上傳過程中避免刷新頁面,或者提供其他手段來處理上傳中斷的情況,如支持?jǐn)帱c續(xù)傳功能。

使用 localStorage 實現(xiàn)斷點續(xù)傳的demo:

const input = document.getElementById('file-input');
const FILE_STORAGE_KEY = 'uploadedFile';

// 讀取本地存儲的文件對象信息
const storedFile = localStorage.getItem(FILE_STORAGE_KEY);
let file = null;

if (storedFile) {
  // 如果存在已上傳的文件信息,則恢復(fù)上傳任務(wù)
  file = JSON.parse(storedFile);
}

input.addEventListener('change', function() {
  file = input.files[0];
  // 將文件對象保存到本地存儲
  localStorage.setItem(FILE_STORAGE_KEY, JSON.stringify(file));
  startUpload();
});

function startUpload() {
  if (!file) {
    console.log('請先選擇文件');
    return;
  }

  const formData = new FormData();
  formData.append('file', file);

  axios.post('/upload', formData, {
    onUploadProgress: function(progressEvent) {
      // 處理上傳進度變化
      if (progressEvent.lengthComputable) {
        const percentComplete = progressEvent.loaded / progressEvent.total * 100;
        console.log(percentComplete.toFixed(2) + '% 已上傳');
      }
    }
  }).then(function(response) {
    // 處理上傳完成事件
    console.log('上傳完成');
    console.log(response.data);
    
    // 上傳完成后,清除本地存儲的文件信息
    localStorage.removeItem(FILE_STORAGE_KEY);
  }).catch(function(error) {
    // 處理上傳錯誤事件
    console.error('上傳出錯');
  });
}

// 監(jiān)聽頁面刷新事件
window.addEventListener('beforeunload', function(event) {
  if (file) {
    // 中止當(dāng)前的上傳請求
    // ...
    
    // 移除本地存儲的文件信息
    localStorage.removeItem(FILE_STORAGE_KEY);
  }
});

使用 localStorage 存儲已選擇的文件對象信息,并在頁面刷新時恢復(fù)該信息。當(dāng)用戶重新選擇文件時,更新文件對象并保存到 localStorage 中。在上傳過程中,如果用戶刷新頁面,會觸發(fā) beforeunload 事件,我們可以在該事件中中止上傳請求并移除 localStorage 中的文件信息。 

其他問題 之 某個切片上傳失敗怎么辦

1. 重新上傳該切片:如果上傳失敗的切片是由于網(wǎng)絡(luò)等原因?qū)е碌模瑒t可以嘗試重新上傳該切片。如果上傳失敗的切片數(shù)量較少,則可以通過手動重試的方式來完成。如果上傳失敗的切片數(shù)量較多,則可能需要設(shè)計一些自動化機制來處理重傳邏輯,如使用隊列等數(shù)據(jù)結(jié)構(gòu)來記錄上傳失敗的切片并進行重傳。

2. 跳過該切片:如果上傳失敗的切片數(shù)量較多,或者由于某些原因無法進行重傳,則可以考慮跳過該切片。具體實現(xiàn)方法可以根據(jù)上傳任務(wù)的特點來確定,如將上傳任務(wù)分為多個階段,每個階段上傳一定數(shù)量的切片,如果某個階段上傳失敗,則跳過該階段并記錄下失敗的切片信息,待后續(xù)再進行重傳。

3. 放棄上傳任務(wù):如果上傳失敗的切片數(shù)量較多,或者重傳操作多次仍然無法恢復(fù)上傳任務(wù),則可以考慮放棄上傳任務(wù)。在此情況下,可以將上傳任務(wù)標(biāo)記為“失敗”狀態(tài),并記錄下失敗的切片信息。如果需要重新上傳該文件,則可以在下一次上傳任務(wù)中,首先檢查之前已上傳的切片信息,如果存在已上傳的切片,則可以直接跳過這些切片并進行后續(xù)的上傳操作。

總結(jié)

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

相關(guān)文章

  • JavaScript實現(xiàn)JSON合并操作示例【遞歸深度合并】

    JavaScript實現(xiàn)JSON合并操作示例【遞歸深度合并】

    這篇文章主要介紹了JavaScript實現(xiàn)JSON合并操作,結(jié)合實例形式分析了javascript基于遞歸深度實現(xiàn)json合并操作相關(guān)實現(xiàn)技巧與注意事項,需要的朋友可以參考下
    2018-09-09
  • 微信小程序教程系列之頁面跳轉(zhuǎn)和參數(shù)傳遞(6)

    微信小程序教程系列之頁面跳轉(zhuǎn)和參數(shù)傳遞(6)

    這篇文章主要為大家詳細(xì)介紹了微信小程序教程系列之頁面跳轉(zhuǎn)和參數(shù)傳遞,微信小程序提供了3種頁面跳轉(zhuǎn)方法,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2017-04-04
  • javascript簡單事件處理和with用法介紹

    javascript簡單事件處理和with用法介紹

    本文為大家介紹下javascript事件處理及with用法,主要是鼠標(biāo)點擊與移動,感興趣的朋友可以參考下
    2013-09-09
  • contains和compareDocumentPosition 方法來確定是否HTML節(jié)點間的關(guān)系

    contains和compareDocumentPosition 方法來確定是否HTML節(jié)點間的關(guān)系

    一個很棒的 blog 文章,是 PPK 兩年前寫的,文章中解釋了 contains() 和 compareDocumentPosition() 方法運行在他們各自的瀏覽器上。
    2011-09-09
  • JavaScript實現(xiàn)星座查詢功能 附詳細(xì)代碼

    JavaScript實現(xiàn)星座查詢功能 附詳細(xì)代碼

    最近小編在做一個項目,其中涉及到一個模塊關(guān)于星座查詢功能,即在文本框中輸入一個生日值,點擊按鈕可以得到對應(yīng)的星座,怎么實現(xiàn)這個需求呢?下面小編通過示例代碼給大家介紹下,需要的朋友參考下吧
    2021-11-11
  • JavaScript 實現(xiàn) Tab 點擊切換實例代碼

    JavaScript 實現(xiàn) Tab 點擊切換實例代碼

    Tab 選項卡切換效果在現(xiàn)如今的網(wǎng)頁中,運用的也是比較多的,包括點擊切換、滑動切換、延遲切換、自動切換等多種效果,在這篇博文里,我們是通過原生 JavaScript 來實現(xiàn) Tab 點擊切換的效果。
    2017-03-03
  • JavaScript Generator函數(shù)使用分析

    JavaScript Generator函數(shù)使用分析

    生成器Generator是JavaScript ES6引入的特性,它讓我們可以分段執(zhí)行一個函數(shù)。但是在談?wù)撋善鳎℅enerator)之前,我們要先了解迭代器Iterator
    2022-10-10
  • JavaScript字典與集合詳解

    JavaScript字典與集合詳解

    這篇文章主要介紹了JavaScript字典與集合詳解,集合是由一組無序且不重復(fù)的元素構(gòu)成。我們可以將集合看成一種特殊的數(shù)組,它的特殊之處就是無序且不重復(fù),這也就意味著我們不能通過下標(biāo)的方式進行訪問,而且集合中不會出現(xiàn)重復(fù)的元素
    2022-07-07
  • 在uniapp中custombar的使用步驟

    在uniapp中custombar的使用步驟

    在 UniApp中,自定義TabBar是指替換默認(rèn)的Tab欄以實現(xiàn)更多個性化的設(shè)計,自定義 TabBar 可以通過創(chuàng)建一個新的組件來實現(xiàn),并在頁面中引用該組件,下面給大家介紹在uniapp中custombar的使用步驟,感興趣的朋友一起看看吧
    2024-05-05
  • 12個非常有創(chuàng)意的JavaScript小游戲

    12個非常有創(chuàng)意的JavaScript小游戲

    JavaScript 在Web開發(fā)過程中已經(jīng)是必不可少的重要分子,他推動著Web的交互性往越來越高的層次發(fā)展,現(xiàn)在的很多Web游戲也基于這類語言開發(fā)。
    2010-03-03

最新評論

博爱县| 齐河县| 福清市| 砚山县| 忻州市| 石阡县| 青海省| 延安市| 耿马| 台南县| 外汇| 甘谷县| 交口县| 宝坻区| 巴彦淖尔市| 疏勒县| 长寿区| 安仁县| 合肥市| 阿城市| 明光市| 武安市| 耿马| 犍为县| 菏泽市| 河北省| 梅州市| 咸丰县| 滁州市| 晋宁县| 郧西县| 江华| 大悟县| 河北区| 鄂温| 凤凰县| 德令哈市| 古丈县| 台南县| 南通市| 毕节市|