前端干全栈实现大文件上传

简介: 前端干全栈实现大文件上传

前言

个人项目中加一个小需求,上传功能原来是只能上传图片,现在需要支持视频等其他类型文件上传,并且支持大文件上传,这里记录分享前端用原生js,后端用node的实现过程

思考

图片上传和其他类型文件上传以及大文件上传区别有什么?

我的理解是如果都是小文件,整个上传实现方面是前后端的技术实现方面没有区别的,可能有的会对文件类型做限制,例如必须是图片之类的;如果是大文件,使用分片上传和断点续传等技术,否则会导致 网络阻塞  浏览器卡顿  服务器压力大 等情况

实现思路

其他类型文件上传和普通的图片上传没区别,如果有图片限制只需要把图片类型的校验限制去掉就行

大文件上传需要前端先将上传的文件切片,然后再依次上传文件切片,上传完所有的切片后,发请求告诉服务端,把上传的所有切片按顺序合并,得到原文件

代码实现

前端

获取文件并切分

获取文件使用 input 标签设置 type=file

<input id="file" type="file" />

upload 按钮点击上传文件, 点击事件中获取input 中选中的文件,将文件按1M的大小使用file.slice()进行切分,得到分块数量

let blockSize = 1024 * 1024; 
let blockCount = Math.ceil(file.size / blockSize);
let block = file.slice(i * blockSize, (i + 1) * blockSize);

上传文件

上传函数使用js原生实现,这里使用 fetch (也可以使用 XMLHttpRequest 对象)上传文件

注意!image 参数要和服务端的参数保持一致,否则上传失败

const formData = new FormData();
formData.append("image", block, fileName);
formData.append("block_index", i + 1);
fetch(ipAddress + "/upload_large_file", {
  method: "post",
  body: formData,
})

大文件被切分成了多个块,根据分块数量循环上传,为了避免一次性发送大量请求导致请求失败,使用async await 同步的方式一个个文件上传,并记录文件名

...
for (let i = 0; i < blockCount; i++) {
    await new Promise((resolve, reject) => {
        fetch()
...

前端把所有切块文件上传完成后,把记录的文件名数组发送给node服务端,node服务端根据文件数组合并后返回结果,到这里前端上传部分就完成了

前端完整代码

github.com/gywgithub/F…

后端

接收切块文件

node后端部分实现的是两部分,先是接收上传的文件保存到服务器的指定位置

const upload = multer({
  limits: { fileSize: 1024 * 1024 * 5 }
});
app.post("/upload_large_file", upload.single("image"), (req, res) => {
  const des_file = __dirname + "/public/images/" + req.files[0].originalname;
  fs.readFile(req.files[0].path, (err, data) => {
    fs.writeFile(des_file, data, (err) => {
      ...
    });
  });
});

这里使用使用了 multer 中间件处理文件,使用 upload.single('image') 处理单个文件的上传(也能实现其他功能,例如对上传文件类型进行过滤),设置单个文件最大为5M,上传的文件读取后保存到 /public/images/ 目录下面

注意!/public/images/ 目录需要提前创建

合并切块文件

前端上传完所有切块文件后,发合并请求通知服务端,服务端根据前端传递的文件切块列表进行文件切块合并

...
  const files = filePaths;
  const targetFile = mergedFileName;
  const writeStream = fs.createWriteStream(targetFile);
  files.forEach((file, index) => {
    const filePath = path.join(__dirname, file);
    const readStream = fs.createReadStream(filePath);
    readStream.pipe(writeStream);
  });
...

files 为基于服务端拼接路径后的文件列表,这个列表记录了前端的切片名称以及切块文件顺序,mergedFileName 为合并后的文件名称(原文件名),这里流的方式进行文件合并,使用 fs 模块的 createWriteStream 创建一个可写流,然后将所有切块文件读取流 createReadStream 合并到可读流中,然后将可读流 pipe 写入到可写流中,最终将合并好的文件写入到磁盘,到这里服务端的部分就完成了

后端完整代码

github.com/gywgithub/F…

奇怪的情况

使用一张大小12M的高清图片上传,发现node端合并后的文件打不开, 使用其他类型的大文件上传也同样无法正常打开

原图效果

image.png

上传到服务端后的效果

image.png

文件似乎损坏了,前端通过浏览器控制台输出查看整个过程都执行文件切块都上传成功了

image.png

通过输出的计算切块文件的大小和对比原文件大小,发现文件大小是一致的,都是 12948424,检查服务端保存的切块文件发现只有第一张切块可以访问,其他切块图片都不能正常访问,切块文件和前端上传的一致

image.png

从后端进行排查,通过固定参数的方式,分别进行了 txt 文件和 png 图片文件,发现是可以正常合并的,两个txt文件合并效果如下

image.png

使用图片合并后也能正常打开,虽然图片花了,上面两张为原图,下面为合并图

image.png

测试使用的浏览器版本和系统

  • Google Chrome: 版本 114.0.5735.133(正式版本)(64 位)
  • Microsoft Edge: 版本 114.0.1823.43 (正式版本) (64 位)
  • Windows11

原因分析

通过静态参数在服务端合并排查的方式,可以排除node代码和文件格式异常的异常导致的无法打开的问题,问题可能出现在前端切块那里,查了MDN的文档以及Baidu,Google,ChatGPT等发现都是前端都是用的 file.slice() 进行切分的,也尝试了不同的切块逻辑,发现最后都是文件无法正常打开,社区的大佬们一起看看分析分析

有掘友遇到过类似问题吗?欢迎探讨交流

目录
相关文章
|
Cloud Native 前端开发 JavaScript
前端开发者必看:不懂云原生你就OUT了!揭秘如何用云原生技术提升项目部署与全栈能力
【10月更文挑战第23天】随着云计算的发展,云原生逐渐成为技术热点。前端开发者了解云原生有助于提升部署与运维效率、实现微服务化、掌握全栈开发能力和利用丰富技术生态。本文通过示例代码介绍云原生在前端项目中的应用,帮助开发者更好地理解其重要性。
423 0
|
JavaScript 前端开发 Docker
前端全栈之路Deno篇(二):几行代码打包后接近100M?别慌,带你掌握Deno2.0的安装到项目构建全流程、剖析构建物并了解其好处
在使用 Deno 构建项目时,生成的可执行文件体积较大,通常接近 100 MB,而 Node.js 构建的项目体积则要小得多。这是由于 Deno 包含了完整的 V8 引擎和运行时,使其能够在目标设备上独立运行,无需额外安装依赖。尽管体积较大,但 Deno 提供了更好的安全性和部署便利性。通过裁剪功能、使用压缩工具等方法,可以优化可执行文件的体积。
1079 3
前端全栈之路Deno篇(二):几行代码打包后接近100M?别慌,带你掌握Deno2.0的安装到项目构建全流程、剖析构建物并了解其好处
|
存储 前端开发 JavaScript
WEB前端开发中如何实现大文件上传?
WEB前端开发中如何实现大文件上传?
1744 3
WEB前端开发中如何实现大文件上传?
|
JavaScript 前端开发 测试技术
前端全栈之路Deno篇(五):如何快速创建 WebSocket 服务端应用 + 客户端应用 - 可能是2025最佳的Websocket全栈实时应用框架
本文介绍了如何使用Deno 2.0快速构建WebSocket全栈应用,包括服务端和客户端的创建。通过一个简单的代码示例,展示了Deno在WebSocket实现中的便捷与强大,无需额外依赖,即可轻松搭建具备基本功能的WebSocket应用。Deno 2.0被认为是最佳的WebSocket全栈应用JS运行时,适合全栈开发者学习和使用。
893 7
|
缓存 前端开发 JavaScript
前端的全栈之路Meteor篇(二):容器化开发环境下的meteor工程架构解析
本文详细介绍了使用Docker创建Meteor项目的准备工作与步骤,解析了容器化Meteor项目的目录结构,包括工程准备、环境配置、容器启动及项目架构分析。提供了最佳实践建议,适合初学者参考学习。项目代码已托管至GitCode,方便读者实践与交流。
280 5
|
存储 前端开发 JavaScript
前端的全栈之路Meteor篇(四):RPC方法注册及调用-更轻量的服务接口提供方式
RPC机制通过前后端的`callAsync`方法实现了高效的数据交互。后端通过`Meteor.methods()`注册方法,支持异步操作;前端使用`callAsync`调用后端方法,代码更简洁、易读。本文详细介绍了Methods注册机制、异步支持及最佳实践。
349 3
|
JavaScript 前端开发 Docker
前端的全栈之路Meteor篇(一):开发环境的搭建 -全局安装或使用容器镜像
本文介绍了如何搭建 Meteor 开发环境,包括全局安装 Meteor 工具和使用 Docker 镜像两种方法,以及创建和运行一个简单的 Meteor 项目的基本步骤。 Meteor 是一个全栈 JavaScript 框架,适用于构建实时 Web 应用程序。文章还提供了遇到问题时的解决建议和调试技巧。
909 3
|
前端开发 JavaScript 中间件
前端全栈之路Deno篇(四):Deno2.0如何快速创建http一个 restfulapi/静态文件托管应用及oak框架介绍
Deno 是由 Node.js 创始人 Ryan Dahl 开发的新一代 JavaScript 和 TypeScript 运行时,旨在解决 Node.js 的设计缺陷,具备更强的安全性和内置的 TypeScript 支持。本文介绍了如何使用 Deno 内置的 `Deno.serve` 快速创建 HTTP 服务,并详细讲解了 Oak 框架的安装和使用方法,包括中间件、路由和静态文件服务等功能。Deno 和 Oak 的结合使得创建 RESTful API 变得高效且简便,非常适合快速开发和部署现代 Web 应用程序。
606 2
|
JavaScript 前端开发 Serverless
前端全栈之路Deno篇:Deno2.0与Bun对比,谁更胜一筹?可能Deno目前更适合serverless业务
在前端全栈开发中,Deno 2.0 和 Bun 作为新兴的 JavaScript 运行时,各自展现了不同的优势。Deno 2.0 重视安全性和多平台兼容性,尤其是对 Windows 的良好支持和原生 TypeScript 支持;而 Bun 则以卓越的性能和简便的开发体验著称,适合快速迭代的小型项目。两者在不同场景下各具特色,Deno 更适合企业级应用和serverless,Bun 则适用于追求速度的项目。
2127 2
|
JSON 分布式计算 前端开发
前端的全栈之路Meteor篇(七):轻量的NoSql分布式数据协议同步协议DDP深度剖析
本文深入探讨了DDP(Distributed Data Protocol)协议,这是一种在Meteor框架中广泛使用的发布/订阅协议,支持实时数据同步。文章详细介绍了DDP的主要特点、消息类型、协议流程及其在Meteor中的应用,包括实时数据同步、用户界面响应、分布式计算、多客户端协作和离线支持等。通过学习DDP,开发者可以构建响应迅速、适应性强的现代Web应用。
1899 2

热门文章

最新文章

  • 1
    前端如何存储数据:Cookie、LocalStorage 与 SessionStorage 全面解析
    832
  • 2
    【CSS】前端三大件之一,如何学好?从基本用法开始吧!(九):强势分析Animation动画各类参数;从播放时间、播放方式、播放次数、播放方向、播放状态等多个方面,完全了解CSS3 Animation
    372
  • 3
    【CSS】前端三大件之一,如何学好?从基本用法开始吧!(八):学习transition过渡属性;本文学习property模拟、duration过渡时间指定、delay时间延迟 等多个参数
    295
  • 4
    【CSS】前端三大件之一,如何学好?从基本用法开始吧!(七):学习ransform属性;本文学习 rotate旋转、scale缩放、skew扭曲、tanslate移动、matrix矩阵 多个参数
    259
  • 5
    【CSS】前端三大件之一,如何学好?从基本用法开始吧!(六):全方面分析css的Flex布局,从纵、横两个坐标开始进行居中、两端等元素分布模式;刨析元素间隔、排序模式等
    380
  • 6
    【CSS】前端三大件之一,如何学好?从基本用法开始吧!(五):背景属性;float浮动和position定位;详细分析相对、绝对、固定三种定位方式;使用浮动并清除浮动副作用
    535
  • 7
    【CSS】前端三大件之一,如何学好?从基本用法开始吧!(四):元素盒子模型;详细分析边框属性、盒子外边距
    495
  • 8
    【CSS】前端三大件之一,如何学好?从基本用法开始吧!(三):元素继承关系、层叠样式规则、字体属性、文本属性;针对字体和文本作样式修改
    177
  • 9
    【CSS】前端三大件之一,如何学好?从基本用法开始吧!(二):CSS伪类:UI伪类、结构化伪类;通过伪类获得子元素的第n个元素;创建一个伪元素展示在页面中;获得最后一个元素;处理聚焦元素的样式
    435
  • 10
    【CSS】前端三大件之一,如何学好?从基本用法开始吧!(一):CSS发展史;CSS样式表的引入;CSS选择器使用,附带案例介绍
    333