前端文件上传(文件上传,分片上传,断点续传)

这篇具有很好参考价值的文章主要介绍了前端文件上传(文件上传,分片上传,断点续传)。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

普通文件上传

思路:

首先获取用户选择的文件对象,并将其添加到一个 FormData 对象中。然后,使用 axios 的 post 方法将 FormData 对象发送到服务器。在 thencatch 中,我们分别处理上传成功和失败的情况,并输出相应的信息。

需要注意,在使用 axios 进行文件上传时,必须将数据格式设置为 multipart/form-data,否则文件对象将无法正确传输。

传统方式:

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("上传成功");
    });
  }
}

分片上传

分片上传是将一个大文件切分成多个小块,然后将这些小块逐个上传到服务器的一种上传方式。

思路:

简单来说就是三个步骤:分片=》并行/串行发送分片=》合并请求

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

分片上传解决以下几个问题:

1. 大文件上传容易导致网络传输中断:当我们尝试上传一个大文件时,如果网络连接不稳定或上传过程中出现异常,整个文件都需要重新上传。而通过分片上传,即使某个小块上传失败,只需要重新上传该小块,而不必重新上传整个文件。

2. 降低服务器压力:如果直接上传一个大文件,服务器需要同时处理大量的数据,并且需要分配较大的内存空间来存储这些数据。而通过分片上传,可以将服务器的负载分散到多个小块的处理上,减轻了服务器的压力。

3. 提高上传速度和稳定性:将大文件切分成小块后,可以并行上传这些小块,从而提高上传速度。同时,如果某个小块上传失败,可以重试该小块,而不会影响其他小块的上传,从而提高上传的稳定性。

4. 支持断点续传:通过分片上传,服务器可以保存每个小块的上传状态,包括已上传的字节数和已确认的小块。如果上传过程中断,下次可以从上次中断的位置继续上传,实现断点续传的功能。

具体实现思路:

  • 将大文件转换成二进制流的格式
  • 利用流可以切割的属性,将二进制流切割成多份
  • 组装和分割块同等数量的请求块(或同等大小的请求块),并行或串行的形式发出请求
  • 待我们监听到所有请求都成功发出去以后,再给服务端发出一个合并的信号

 一般我会选择在文件小于5MB时普通文件上传,当文件大于5MB时进行分片上传。

前端分片上传,JavaScript,前端

前端分片上传,JavaScript,前端

整体逻辑就是:

前端分片上传,JavaScript,前端

将大文件进行分片

我这里封装了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();
};

 因为我实现了多文件并行分片上传,所以这里在将文件加入列表时我就已经计算好了相关属性

当md5计算完毕,文件显示准备就绪。

前端分片上传,JavaScript,前端

创建切片请求:

前端分片上传,JavaScript,前端

返回结果的属性之一exist反应该文件是否上传过,如果存在,则可以实现秒传,无需再次上传。

如果不存在,则获取此次上传的目标ip和端口号

前端分片上传,JavaScript,前端

将每一个切片 并行/串行 的方式发出:

我这里使用promise实现了并行(如果是用循环遍历切片串行传输,可以通过循环下标i的值与切片总数相等来判断分片是否上传完毕)

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

前端分片上传,JavaScript,前端

当所有分片上传完成后。再给服务器端发送合并请求。

文件合并请求:

前端分片上传,JavaScript,前端前端分片上传,JavaScript,前端


断点续传

在分片上传的基础上,我们很容易考虑到断点续传的需求。

思路:

点击暂停按钮时停止上传。点击继续上传,继续上传剩下的分片或请求。

我们很容易想到给每个分片一个是否上传的状态标识来识别该分片是否上传完成。

法1:初始时所有分片的状态为未上传,当一个分片上传完成,将该标识设置为已上传。暂停上传时,将当前上传的分片也设置为未上传;重新进行上传时,就可以继续把其他未上传的分片上传了。

法2:将所有分片加入一个列表中,每当成功上传一个分片,就将该分片从列表中删除。而列表中剩下的分片就是还未上传的分片。


秒传

即前面分片上传中提到的。发送创建分片请求时,让服务器检查该文件是否上传过,如果是,则无需重复上传,直接显示上传成功实现秒传功能。


其他问题 之 上传过程中刷新页面怎么办

如果在上传过程中刷新了页面,通常会导致上传任务中断。

因为刷新页面会导致浏览器重新加载页面,之前的 JavaScript 代码和网络请求都会被取消。

当页面刷新后,可以尝试使用以下方法来处理上传任务的中断情况:

1. 利用浏览器的缓存机制:在上传之前,将文件对象保存到浏览器的本地存储或会话存储中。当页面刷新后,通过读取缓存中的文件对象信息,重新构建上传任务,并恢复之前的上传进度。

2. 检测页面刷新事件:可以通过监听 `beforeunload` 事件来捕获页面刷新的操作。在该事件触发时,可以弹出一个确认框,提示用户是否继续离开页面。如果用户选择离开页面,可以先中止当前的上传请求,然后再进行页面刷新。

该方法并不能完全保证上传任务的连续性和完整性。在实际应用中,为了确保上传任务的可靠性,通常建议在上传过程中避免刷新页面,或者提供其他手段来处理上传中断的情况,如支持断点续传功能。

使用 localStorage 实现断点续传的demo:

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

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

if (storedFile) {
  // 如果存在已上传的文件信息,则恢复上传任务
  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('上传出错');
  });
}

// 监听页面刷新事件
window.addEventListener('beforeunload', function(event) {
  if (file) {
    // 中止当前的上传请求
    // ...
    
    // 移除本地存储的文件信息
    localStorage.removeItem(FILE_STORAGE_KEY);
  }
});

使用 localStorage 存储已选择的文件对象信息,并在页面刷新时恢复该信息。当用户重新选择文件时,更新文件对象并保存到 localStorage 中。在上传过程中,如果用户刷新页面,会触发 beforeunload 事件,我们可以在该事件中中止上传请求并移除 localStorage 中的文件信息。 


其他问题 之 某个切片上传失败怎么办

1. 重新上传该切片:如果上传失败的切片是由于网络等原因导致的,则可以尝试重新上传该切片。如果上传失败的切片数量较少,则可以通过手动重试的方式来完成。如果上传失败的切片数量较多,则可能需要设计一些自动化机制来处理重传逻辑,如使用队列等数据结构来记录上传失败的切片并进行重传。

2. 跳过该切片:如果上传失败的切片数量较多,或者由于某些原因无法进行重传,则可以考虑跳过该切片。具体实现方法可以根据上传任务的特点来确定,如将上传任务分为多个阶段,每个阶段上传一定数量的切片,如果某个阶段上传失败,则跳过该阶段并记录下失败的切片信息,待后续再进行重传。

3. 放弃上传任务:如果上传失败的切片数量较多,或者重传操作多次仍然无法恢复上传任务,则可以考虑放弃上传任务。在此情况下,可以将上传任务标记为“失败”状态,并记录下失败的切片信息。如果需要重新上传该文件,则可以在下一次上传任务中,首先检查之前已上传的切片信息,如果存在已上传的切片,则可以直接跳过这些切片并进行后续的上传操作。文章来源地址https://www.toymoban.com/news/detail-835711.html

到了这里,关于前端文件上传(文件上传,分片上传,断点续传)的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • minio&前后端分离上传视频/上传大文件——前后端分离断点续传&minio分片上传实现

    🍀🍀🍀🍀分布式文件系统-minio: 第一章:分布式文件系统介绍与minio介绍与使用(附minio java client 使用) 第二章:minio前后端分离上传视频/上传大文件——前后端分离断点续传minio分片上传实现 断点续传指的是在下载或上传时,将下载或上传任务(一个文件或一个压缩包

    2024年02月03日
    浏览(54)
  • 【SpringBoot整合系列】SpringBoot 实现大文件分片上传、断点续传及秒传

    小文件(图片、文档、视频)上传可以直接使用很多ui框架封装的上传组件,或者自己写一个input 上传,利用FormData 对象提交文件数据,后端使用spring提供的MultipartFile进行文件的接收,然后写入即可。 但是对于比较大的文件,比如上传2G左右的文件(http上传),就需要将文件

    2024年04月16日
    浏览(67)
  • springboot整合vue2-uploader文件分片上传、秒传、断点续传

    vue-simple-uploader 是基于 simple-uploader.js 封装的vue上传插件。它的优点包括且不限于以下几种: 支持文件、多文件、文件夹上传;支持拖拽文件、文件夹上传 可暂停、继续上传 错误处理 支持“秒传”,通过文件判断服务端是否已存在从而实现“秒传” 分片上传 支持进度、预估

    2024年02月06日
    浏览(61)
  • 基于vue-simple-uploader封装文件分片上传、秒传及断点续传的全局上传

    1. 前言 文件上传 小文件(图片、文档、视频)上传可以直接使用很多ui框架封装的上传组件,或者自己写一个input 上传,利用FormData 对象提交文件数据,后端使用spring提供的MultipartFile进行文件的接收,然后写入即可。但是对于比较大的文件,比如上传2G左右的文件(http上传

    2024年02月06日
    浏览(48)
  • 【万字长文】Vue+SpringBoot实现大文件秒传、断点续传和分片上传完整教程(提供Gitee源码)

    前言:最近在实际项目中碰到一个需求,客户可能会上传比较大的文件,如果采用传统的文件上传方案可能会存在服务器压力大、资源浪费甚至内存溢出的一些安全风险,所以为了解决一系列问题,需要采用新的技术方案来实现大文件的上传;空闲的时候参考了网上的一些相

    2024年02月12日
    浏览(47)
  • springboot 、html分片上传,断点续传

    后端代码 注意:合并分片代码中: Files.write(mergedFilePath, Files.readAllBytes(chunkFilePath), StandardOpenOption.APPEND); 如果不设置该值 StandardOpenOption.APPEND ,无法打开合并后的文件 前端代码

    2024年02月05日
    浏览(46)
  • SpringBoot整合minio实现断点续传、分片上传(附源码)

    在Web开发中,大文件的上传是必不可少的功能之一。本文将介绍如何使用SpringBoot整合minio实现一个简单的大文件上传网站。 项目下载 gitee:https://gitee.com/wusupweilgy/springboot-vue.git 前端:vue2、element-ui组件、axios 后端:springboot、minio、mybatis-plus、redis 断点续传 分片上传 前端显示

    2024年02月04日
    浏览(52)
  • javaScript实现客户端直连华为云OBS实现文件上传、断点续传、断网重传

    写在前面:在做这个调研时我遇到的需求是前端直接对接华为云平台实现文件上传功能。上传视频文件通常十几个G、客户工作环境网络较差KB/s,且保证上传是稳定的,支持网络异常断点重试、文件断开支持二次拖入自动重传等。综合考虑使用的华为云的分段上传功能,基于

    2024年02月20日
    浏览(42)
  • Spring Boot整合Minio实现上传凭证、分片上传、秒传和断点续传

    Spring Boot整合Minio后,前端的文件上传有两种方式: 文件上传到后端,由后端保存到Minio 这种方式好处是完全由后端集中管理,可以很好的做到、身份验证、权限控制、文件与处理等,并且可以做一些额外的业务逻辑,比如生成缩略图、提取元数据等。 缺点也很明显: 延迟时

    2024年02月04日
    浏览(48)
  • 【前端面试】中大文件上传/下载:中等文件代理服务器放行+大文件切片传输+并发请求+localstorage实现断点续传

    目录 切片上传~spark-md5 原理:流式计算+分块处理 文件标识spark-md5:A-B A.切片哈希值合并 B.首尾切片+其他切片前中后各取2M 计算hash:A-B(参考React的Fiber架构) A.线程:web-worker B.空闲:requestIdleCallback 异步并发控制:A-B(参考http2的多路复用) A.promise.allSettled() B.并发数max=

    2024年02月12日
    浏览(56)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包