網站首頁 編程語言 正文
最近做了大文件(文件夾)分片上傳的需求,記錄一下。
原理
前端進行大文件分片上傳的方案幾乎都是利用Blob.prototype.slice方法對文件進行分片,用數組將每一個分片存起來,最后將分片發給后端。由于并發的原因,需要給每個分片給定index,方便后端進行拼接。
方案
我在做需求之前看了網上的一些方案,大多數是前端進行分片、發送分片,在發送完所有分片請求之后,再給后端發送一個合并文件的請求。但其實也可以在發送分片之前就先把文件的一些信息(整個文件的MD5、分片個數、分片大小、分片的MD5等等)先發給后端,后端在接收完分片之后就可以自動合并了。
antd Upload
先介紹一下antd中的Upload組件,Upload的API中有一個beforeUpload
,該函數接收兩個參數,file和fileList,file是一個文件對象,類型是File,屬于Blob的子類,所以可以直接調用file.slice進行分片。值得注意的是,beforeUpload
這個鉤子可能會調用多次,比如你上傳一個文件夾,文件夾中有5個文件,那么它就會調用5次。
file文件對象長這樣:
文件分片
上面已經說到,可以直接調用file.slice,所以可以在beforeUpload
中進行分片,比如:
const createFileChunk = async (file: Blob, size: number) => { const fileChunkList = []; let cur = 0; let index = 0; while (cur < file.size) { const chunk = file.slice(cur, cur + size); fileChunkList.push({ file: chunk, index }); // 可以加入很多信息。比如MD5 cur += size; index += 1; } return fileChunkList; }; const beforeUpload = (file: Blob) => { const fileChunkList = createFileChunk(file); // 其他自定義邏輯 return true }
MD5
在分片中加入MD5主要是為了后端收到文件后進行校驗,要注意的是,Blob對象是不能夠作為MD5函數的參數的,一般是用FileReader把Blob讀成二進制之后再傳入MD5函數,比如:
import md5 from 'md5'; const getFileMd5 = (chunk: Blob) => { return new Promise((resolve, reject) => { const reader = new FileReader(); reader.readAsArrayBuffer(chunk); reader.onload = (data) => { resolve(md5(new Uint8Array(data.target?.result as any))); }; reader.onerror = () => { reject(new Error('Failed to read file!')); }; }); };
發送分片請求
二進制文件的上傳請求是不能用json傳的,如果一定要用json,可以把文件轉成base64(這里不適用,適用于小文件)。
這里附上二進制文件轉base64的方法:
const fileToBase64 = (file: Blob): Promise<string> => { return new Promise((resolve) => { const reader = new FileReader(); reader.readAsDataURL(file); reader.onload = (e) => { if (e && e.target && e.target.result) { resolve(e.target.result); } }; }); };
對于文件上傳的請求,需要用到FormData,http請求頭中的Content-Type
要設置為multipart/form-data
,比如:
const formData = new FormData(); formData.append('file', file); // file為Blob對象
然后把formData作為http請求的body就可以進行發送了
顯示上傳進度
我這里使用的方案是 已上傳的分片數量 / 總的分片數量,這是一種大概的上傳進度,忽略了單個分片上傳的進度,因為是大文件,也沒有必要計算得十分準確。
此外還有錯誤重傳、限制請求并發數、斷點續傳等邏輯,本文不再闡述。
原文鏈接:https://blog.csdn.net/Kobe_G/article/details/127752907
相關推薦
- 2022-02-05 ERROR 1205 (HY000): Lock wait timeout exceeded; tr
- 2022-03-24 C++關于指針,繼承和多態介紹_C 語言
- 2022-09-30 Go語言編譯原理之變量捕獲_Golang
- 2022-07-14 C++實現一個簡單的線程池的示例代碼_C 語言
- 2023-02-23 Android開發之BottomSheetDialog組件的使用_Android
- 2023-04-02 Python中time庫的使用(日期時間)_python
- 2022-12-04 pyecharts如何旋轉折線圖的X軸標簽_python
- 2023-03-28 Python代碼庫之Tuple如何append添加元素問題_python
- 最近更新
-
- window11 系統安裝 yarn
- 超詳細win安裝深度學習環境2025年最新版(
- Linux 中運行的top命令 怎么退出?
- MySQL 中decimal 的用法? 存儲小
- get 、set 、toString 方法的使
- @Resource和 @Autowired注解
- Java基礎操作-- 運算符,流程控制 Flo
- 1. Int 和Integer 的區別,Jav
- spring @retryable不生效的一種
- Spring Security之認證信息的處理
- Spring Security之認證過濾器
- Spring Security概述快速入門
- Spring Security之配置體系
- 【SpringBoot】SpringCache
- Spring Security之基于方法配置權
- redisson分布式鎖中waittime的設
- maven:解決release錯誤:Artif
- restTemplate使用總結
- Spring Security之安全異常處理
- MybatisPlus優雅實現加密?
- Spring ioc容器與Bean的生命周期。
- 【探索SpringCloud】服務發現-Nac
- Spring Security之基于HttpR
- Redis 底層數據結構-簡單動態字符串(SD
- arthas操作spring被代理目標對象命令
- Spring中的單例模式應用詳解
- 聊聊消息隊列,發送消息的4種方式
- bootspring第三方資源配置管理
- GIT同步修改后的遠程分支