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

普通文件上传

思路:

首先获取用户选择的文件对象,并将其添加到一个 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时进行分片上传。

整体逻辑就是:

将大文件进行分片

我这里封装了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计算完毕,文件显示准备就绪。

创建切片请求:

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

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

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

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

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

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

文件合并请求:


断点续传

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

思路:

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

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

法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. 放弃上传任务:如果上传失败的切片数量较多,或者重传操作多次仍然无法恢复上传任务,则可以考虑放弃上传任务。在此情况下,可以将上传任务标记为“失败”状态,并记录下失败的切片信息。如果需要重新上传该文件,则可以在下一次上传任务中,首先检查之前已上传的切片信息,如果存在已上传的切片,则可以直接跳过这些切片并进行后续的上传操作。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/344562.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

VM虚拟机忘记密码,ISO镜像修改

VM虚拟机忘记密码&#xff0c;ISO镜像修改 制作镜像&#xff1a; 镜像已制作&#xff0c;可在文末链接自行获取从镜像启动系统 1&#xff09;添加IOS镜像文件&#xff1a; 2&#xff09;开机进去固件&#xff1a; 进入后选择对应的驱动器启动 3. 修改密码 点击修改密码软件&a…

苹果、VMware、Apache等科技巨头漏洞被大量应用

Therecord网站披露&#xff0c;黑客因频繁利用多个新发现的漏洞发起攻击吸引了美国网络安全专家们的高度关注&#xff0c;专家们担心这些漏洞可能会被网络犯罪组织和其他各国政府用于不法目的。 过去一周&#xff0c;美国网络安全专家和网络安全与基础设施安全局&#xff08;C…

Dify学习笔记-入门学习(二)

1、官方文档链接 https://docs.dify.ai/v/zh-hans/getting-started/readme 2、 Dify基础介绍 Dify 是一款开源的大语言模型(LLM) 应用开发平台。它融合了后端即服务&#xff08;Backend as Service&#xff09;和 LLMOps 的理念&#xff0c;使开发者可以快速搭建生产级的生成…

鲜花商城,Java项目、前端vue

系统架构 后台&#xff1a; SpringBoot Mybatis-plus Mybatis Hutool工具包 lombok插件 前台&#xff1a;Vue Vue Router ELementUI Axios 系统简介 功能&#xff1a;首页推荐&#xff08;默认根据用户买过的商品进行推荐&#xff0c;如果没买过则根据商品销量推荐&…

8种策略教你有效的ddos攻击防御方法

这篇文章讨论了缓解DDoS&#xff08;分布式拒绝服务&#xff09;攻击的最佳实践。DDoS攻击是一种旨在使目标服务器或网络超载而无法正常工作的恶意行为。文章提出了一系列策略来减轻DDoS攻击的影响&#xff0c;包括流量过滤和封堵、负载均衡和弹性扩展、使用CDN&#xff08;内容…

函数递归和迭代(简单认识)

1.递归思想 把一个大型复杂问题层层转化为一个与原问题相似&#xff0c;但规模较小的子问题来求解&#xff1b;直到子问题不能再被拆分&#xff0c;递归就结束了。所以递归的思考方式就是把大事化小的过程。递归中的递就是递推的意思&#xff0c;归就是回归的意思&#xff0c;…

excel 设置密码保户

目录 前言设置打开密码设置编辑密码 前言 保户自己的数据不被泄漏是时常有必要的&#xff0c;例如财务数据中最典型员工工资表&#xff0c;如果不设置密码后果可想而知&#xff0c;下面我们一起来设置excel查看密码和编辑密码。我用的是wps,其它版本类似&#xff0c;可自行查资…

Qt解析含颜色的QString字符串显示到控件

1、需求 开发接收含颜色字符串显示到窗口&#xff0c;可解析字符串颜色配置窗口属性&#xff0c;且分割字符串显示。 mprintf(“xxxxxx”)&#xff1b;打印的xxxxxx含有颜色配置。 2、实现方法 2.1、条件 选用Qt的PlainTextEdit控件显示字符串&#xff0c;配置为只读模式 …

C++笔记(二)

函数的默认参数 如果我们自己传入数据&#xff0c;就用自己的数据&#xff0c;如果没有&#xff0c;就用默认值 语法&#xff1a; 返回值类型 函数名&#xff08;形参默认值&#xff09;{} int func&#xff08;int a&#xff0c;int b20&#xff0c;int c30&#xff09;{} …

[BUG] Authentication Error

前言 给服务器安装了一个todesk&#xff0c;但是远程一直就是&#xff0c;点击用户&#xff0c;进入输入密码界面&#xff0c;还没等输入就自动返回了 解决 服务器是无桌面版本&#xff0c;或者桌面程序死掉了&#xff0c;重新安装就好 sudo apt install xorg sudo apt inst…

C++入门语法———命名空间,缺省参数,重载函数

文章目录 一.命名空间1.存在意义2.语法使用1.定义命名空间2.使用命名空间的三种方式 二.缺省参数1.全缺省参数2.半缺省参数 三.重载函数1.定义2.重载原理———名字修饰 一.命名空间 1.存在意义 C命名空间的主要意义是为了避免命名冲突&#xff0c;尤其是在大型项目中可能存在…

ai伪原创生成器app,一键生成原创文章

近年来&#xff0c;随着人工智能技术的飞速发展&#xff0c;AI伪原创生成器App已经成为了许多写手和创作者们的新宠。这款AI伪原创生成器App以其一键生成原创文章的快速便捷性&#xff0c;正在引起广泛的关注和使用。下面跟随小编一起来了解下吧&#xff01; 随着互联网的普及&…

8 种不同类型的防火墙

一、什么是防火墙&#xff1f; 防火墙是一种监视网络流量并检测潜在威胁的安全设备或程序&#xff0c;作为一道保护屏障&#xff0c;它只允许非威胁性流量进入&#xff0c;阻止危险流量进入。 防火墙是client-server模型中网络安全的基础之一&#xff0c;但它们容易受到以下方…

内网环境pip使用代理服务器安装依赖库

目录 使用proxy参数配置pip代理 使用配置文件配置pip代理 其他 由于公司内部网络无法访问外网导致安装依赖库失败&#xff0c;现将安装方法如下记录。 使用proxy参数配置pip代理 如不使用离线安装方法&#xff0c;可利用pip的--proxy参数进行代理的配置&#xff0c;使用方法…

1.15火星人(全排列+变进制数),涂国旗(搜索)

P1088 [NOIP2004 普及组] 火星人 首先是要得到当前排序的排名&#xff0c;其次是要得到它的排名 n进制就是说满n就进&#xff0c;该位上不可能保持为n&#xff0c;最多保持为n-1&#xff1b; 变进制数 #include<iostream> #include<iomanip> #include<vector…

力扣518. 零钱兑换 II

动态规划 思路&#xff1a; 假设 dp[i] 为金额 i 使用零钱的组合数&#xff0c;其可以由其中的一种零钱 coin 和 i - coin 组合&#xff1b; 遍历零钱数组&#xff0c;对每一种零钱 coin 进行如下操作&#xff1a; 从 coin 到 amount 金额进行遍历&#xff0c;dp[j] dp[j] d…

【深度学习:Collaborative filtering 协同过滤】深入了解协同过滤:技术、应用与示例

此图显示了使用协作筛选预测用户评分的示例。起初&#xff0c;人们会对不同的项目&#xff08;如视频、图像、游戏&#xff09;进行评分。之后&#xff0c;系统将对用户对项目进行评分的预测&#xff0c;而用户尚未评分。这些预测基于其他用户的现有评级&#xff0c;这些用户与…

安全基础~通用漏洞1

文章目录 知识补充Acess数据库注入MySQL数据库PostgreSQL-高权限读写注入MSSQL-sa高权限读写执行注入Oracle 注入Mongodb 注入sqlmap基础命令 知识补充 order by的意义&#xff1a; union 操作符用于合并两个或多个 select语句的结果集。 union 内部的每个 select 语句必须拥有…

k8s详细教程(二)

5. Pod 详解 5.1 Pod 介绍 5.1.1 Pod 结构 每个 Pod 中都可以包含一个或者多个容器&#xff0c;这些容器可以分为两类&#xff1a; 用户程序所在的容器&#xff0c;数量可多可少Pause 容器&#xff0c;这是每个 Pod 都会有的一个根容器&#xff0c;它的作用有两个&#xff1…

感性负载对电路稳定性有什么影响?

感性负载是指带有电感元件的负载&#xff0c;如电动机、变压器等。在电路中&#xff0c;感性负载对电路稳定性有很大的影响。本文将从以下几个方面来分析感性负载对电路稳定性的影响&#xff1a; 当感性负载接通或断开时&#xff0c;会产生一个瞬时电流&#xff0c;这个瞬时电流…