大文件上传原理及实现方案 | 京东物流技术团队

一、什么是大文件 一般,我们传送大文件是指传送大于100M的文件,而普通文件是指小于100M,常见的是20M、30M和50M,两者主要的区别在于文件大小上,还有传送速度上。

一般普通“邮件附件”只能发20M、30M,50M的文件,而几百M的照片、文件、设计图等大文件传送起来就不是那么容易了。

二、大文件跟普通文件上传时的区别 普通文件上传只需要注意两点

1.指定上传的接口地址。 2.将请求头的Content-Type设置成:multipart/form-data,将文件对象以二进制流的形式传给后端

大文件上传时会遇到的问题

1.前后端上传请求超时限制,一次性传输大小限制。 2.网络抖动等,失败后需要重新上传。 3.http1.1版本, TCP连接默认是open的,所有请求都通过同一个连接进行数据传输,如果前面的请求被阻塞了,后面的请求也得不到响应,也叫HTTP/1.1 中的队头阻塞问题,除非建立多个连接,但是多个连接会浪费资源。 4.无进度条,用户体验极差。

三、大文件上传的原理及思路 前端

获取文件的二进制内容,然后对其内容拆分成指定大小的切片文件,最后将每个切片上传到服务端即可。

流程:获取文件 ➡️ 分片 ➡️ 上传

需要优化的点

•中断后无需重新上传(断点续传) •上传过的文件无需上传(秒传) •显示上传进度

后端

根据切片文件的唯一标识在后端将多个相同文件的切片还原成一个文件

流程:获取分片文件 ➡️ 还原分片 ➡️ 返回拼接好的文件信息

需要优化的点

•删除碎片文件 还原切片时需要注意的问题

•在后端需要将多个相同文件的切片还原成一个文件,如果不能识别一个切片是属于哪一个文件的,当同时发生多个请求时,追加的文件内容会出错。 •切片上传接口是异步的,无法保证服务器接收到的切片是按照请求顺序拼接的。 解决办法

1)如何识别多个切片是来自于同一个文件的?

这个可以在发送请求时,为每个切片传递一个相同文件的identifier参数。

2)如何将多个切片还原成一个文件?

什么时候开始拼接:确认所有切片都已上传完后开始进行拼接,这个可以通过客户端在切片全部上传后调用后端定义的mkfile接口来通知服务端进行拼接,或者前端传递切片的总数totalChunks, 服务端判断接收的切片数量如果等于totalChunks的值就开始进行拼接,无须前端通知后端进行拼接。

怎么按顺序拼接:可以在每个切片上标记一个位置索引值,找到同一个context下的所有切片,根据chunkNumber确认每个切片的顺序,这个按顺序拼接切片,还原成文件

上面有几个重要的参数: identifier ,chunkNumber,totalChunks

identifier :我们需要获取为一个文件的唯一标识,可以通过下面两种方式获取

  1. 根据文件名、文件长度等基本信息进行拼接,为了避免多个用户上传相同的文件,可以再额外拼接用户信息如uid等保证唯一性

  2. 根据文件的二进制内容计算文件的hash,这样只要文件内容不一样,则标识也会不一样,缺点在于计算量比较大.

chunkNumber:当前切片的索引

totalChunks:总的切片数

四、大文件上传的实现方案 前端分片代码

// 获取identifier,同一个文件会返回相同的值 function createIdentifiert(file) { return file.name + file.size }

let file = document.querySelector(“[name=file]”).files[0]; const LENGTH = 1024 * 1024 * 1;//1MB let chunks = slice(file, LENGTH);

// 获取对于同一个文件,获取其identifier let identifier = createIdentifier(file);

let tasks = []; chunks.forEach((chunk, index) => { let fd = new FormData(); //传递file对象 fd.append(“file”,chunk); // 传递identifier fd.append(“identifier”, identifier); // 传递切片索引值 fd.append(“chunkNumber”, index + 1); // 传递切片总数 fd.append(“totalChunks”, chunks.length);
tasks.push(post(“/mkblk.php”, fd)); });

// 所有切片上传完毕后,调用mkfile接口 Promise.all(tasks).then(res => { let fd = new FormData(); fd.append(“identifier”, identifier); fd.append(“totalChunks”,chunks.length); post(“/mkfile.php”, fd).then(res => { console.log(res); }) });

后端还原分片代码

// mkblk.php接口 $identifier = $_POST[‘identifier’]; $path = ‘./upload/’ . i d e n t i f i e r ; i f ( ! i s _ d i r ( identifier; if(!is\_dir( identifier;if

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值