# file_upload **Repository Path**: errlei/file_upload ## Basic Information - **Project Name**: file_upload - **Description**: No description available - **Primary Language**: JavaScript - **License**: MIT - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 1 - **Created**: 2022-04-10 - **Last Updated**: 2022-04-18 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README ### 大文件上传 #### 1. 前端 > 1.文件切片 - slice方法, 将文件转换为blob对象,切片数组 - 将切片数组 转换为 便于上传的`FormData`参数,修改切片名称, 然后再转换为请求列表 - 使用`Promise.allSettle`并发所有请求 > 2.封装ajax请求 - 使用`xhr`的基本结构 ` open,send,onload `进行封装 > 1. 进度条 - `xhr`原生支持,监听`upload.onprogress`事件即可,事件对象里面`e.loaded`表示已上传大小 > 文件秒传 - 上传切片钱,先检查上传文件的hash与服务器里面的是否有重复 > 断点续传 - 断点续传的原理在于前端/服务端需要`记住`已上传的切片,这样下次上传就可以跳过之前已上传的部分 - 一般又两种解决方案, 前端使用 `localStorage` 记录已上传的切片 hash, 第二种是服务端保存已上传的切片 hash,前端每次上传前向服务端获取已上传的切片, 一般选择第二种 - 原理是使用 `XMLHttpRequest` 的 `abort` 方法, 暂停就是把切片数组所有已发请求abort,然后清空切片数组 - 续传就是当文件切片上传后,服务端会建立一个文件夹存储所有上传的切片,所以每次前端上传前可以调用一个接口,服务端将已上传的切片的切片名返回,前端再跳过这些已经上传切片,这样就实现了“续传”的效果 #### 2. 后端 - 跨域问题 ``` res.setHeader('Access-Control-Allow-Origin', '*'); res.setHeader('Access-Control-Allow-Header', '*'); ``` - 两个第三方库的使用 `multiparty fs-extra` ``` multiparty.Form(); 接受前端传递过来的文件切片,并改变路径后保存下来 myMultiparty.parse(req, (err, fields, files) =>{}) ``` - 将前端传递过来的chunk包移动到指定的位置 ``` 构建我们的chunk存放路径 target/文件名/chunk名, 生成对应的文件夹, 然后再移动 fse.existsSync 检验目录是否存在 fse.mkdirs 创建文件夹 移动chunk包的位置(multiparty 这个库,给我们接收到前端传递过来的图片文件放置的默认位置),并修改他的名称 fse.move(chunk, `${chunkDir}/${chunkName}`) ``` - 通过流,将chunk包合并为一个文件 ``` 新建方法mergeChunkList(filepath, filename, 0.5 * 1024 * 1024);, 将文件生成到对应的文件夹下 读取所有的chunk文件, fse.readdirSync(chunkDir), 得到一个数组 排序之后再进行合并操作 chunkPaths.sort((a, b) => a.split('-')[1] - b.split('-')[1]); ``` - 创建可写流,将chunk转换为流; 然后创建可读流,将可写流通过pipe方法合并,得到最终文件