前言

对于普通业务场景而言,直接用 FormData() 将文件以入参的一个参数传给后端即可,但此方法有一个弊端就是,有个 30M 的上限。

对于动辄几百 M、几个 G 的文件上传需求,FormData() 显然已经黯然了,但仍想以此方法上传,那么就可以把大文件,按照同一大小进行分片,然后分片上传至后端,上传完后在通知后端进行组装保存即可。

效果先贴出:

  

  

废话不多说,代码见!

前端部分

  js 业务处理代码:(一些细节就不全部贴了,需要自己调试修改喽)

  1   state = {
2 fileList: [],
3 filenameview: "等待上传...",
4 zhuti: "",
5 wenjianfjdz: "",//附件共享盘地址
6 fileuploading: false,
7 disablebtndelete: "none",
8 chunkList: [],//文件切片 List
9 };
10 //创建文件切片//默认大小为 20M 一个片段
11 createFileChunk = (file, size = 20 * 1024 * 1024) => {
12 const fileChunkList = [];
13 let cur = 0;
14 while (cur < file.size) {
15 fileChunkList.push({ file: file.slice(cur, cur + size), name: file.uid });//uid:文件唯一标识
16 cur += size;
17 }
18 return fileChunkList;
19 };
20 //上传文件附件(大文件)
21 uploadloadFileAttachment = ({ file, fileList }) => {
22 this.setState({ fileuploading: true, tipContent: "正在校验文件,请稍后..." });
23 if (this.state.zhuti == null || this.state.zhuti.length == 0) {
24 message.warning("上传文件前,请先填写‘主题’!");this.setState({ fileuploading: false }); return;
 25     }
26 else {
27 if (file.status === "done") {
28 this.setState({ tipContent: "文件已完成校验,上传中,请耐心等待..." });
29 let file = fileList[fileList.length - 1].originFileObj;
30 if (file.size / (1024 * 1024) > 3096) {//设置最大不超过 3G
31 message.warning("附件大小不允许超过 3GB !");
32 this.setState({ fileuploading: false, tipContent: "加载中..." });
33 return;
34 }
35 let filename = file.name;
36 let chunklistcurr = this.createFileChunk(file).map(({ file, name }, index) => {
37 return {
38 chunk: file,
39 size: file.size,
40 percent: 0,
41 name: name,
42 index,
43 };
44 });
45 let filecount = chunklistcurr.length;
46 let ii = 0;
47 chunklistcurr.forEach(element => {//分片传输
48 const formData = new FormData()
49 formData.append('file', element.chunk);
50 formData.append('index', element.index);//片段顺序
51 formData.append('name', element.name);//文件唯一标识
52 formData.append('size', element.size);
53 formData.append('filecount', filecount);//片段总数
54 axios({
55 method: 'post',
56 url: '/api/system/System/UploadFileAttachmentChunk?zhuti=' + this.state.zhuti,
57 data: formData,
58 headers: { "Content-Type": "multipart/form-data" }
59 }).then(({ data }) => {
60 if (data.code == 200) {
61 ii++;//记录已经上传成功的片段数量
62 if (ii == filecount) {//分块全部上传完成
63 let indata = { "name": chunklistcurr[0].name, "filecount": filecount, "filename": filename, "zhuti": this.state.zhuti }
64 axios({//传输完成,通知拼接
65 method: 'post',
66 url: '/api/system/System/CombineChunkToFile',
67 data: indata,
68 headers: { "Content-Type": "application/json" }
69 }).then(({ data }) => {
70 if (data.code == 200) {
71 this.setState({ wenjianfjdz: data.desc.split("|")[0], filenameview: data.desc.split("|")[1], disablebtndelete: "" });//记录返回值
72 message.success(`上传成功!`);
73 }
74 else if (result.code == 202) {
75 window.location.href = "/wellcome";
76 }
77 else {
78 message.error("上传失败,请稍后重试!详情:" + data.desc);
79 }
80 }).catch((err) => {
81 console.log(err);
82 message.error("上传失败,请稍后重试!");
83 }).finally(() => {
84 this.setState({ fileuploading: false, tipContent: "加载中..." });
85 })
86 }
87 }
88 else if (result.code == 202) {
89 window.location.href = "/wellcome";
90 }
91 else {
92 message.error("上传失败,请稍后重试!详情:" + data.desc);
93 return;
94 }
95 }).catch((err) => {
96 console.log(err);
97 message.error("上传失败,请稍后重试!");
98 return;
99 }).finally(() => {
100 })
101 })
102 }
103 else if (file.status === "error") {
104 message.error(`上传失败,请稍后重试!${file.name}`);
105 this.setState({ fileuploading: false, tipContent: "" });
106 }
107 }
108 this.setState({ fileList: [...fileList] });
109 }
110 beforeUploadMethod = () => this.setState({ fileuploading: true, tipContent: "正在校验文件,请稍后..." })

  html 处理代码:(一些细节就不全部贴了,需要自己调试修改喽)

 1   <Upload
2 fileList={fileList}
3 showUploadList={false}
4 onChange={this.uploadloadFileAttachment}
5 style={{ float: "left", lineHeight: "55px" }}
6 >
7 <Button icon={<UploadOutlined />} style={{ margin: "20px 20px 20px 0", display: permissionedit }}>上传附件</Button>
8 </Upload>
9 <Button icon={<DeleteOutlined />} danger style={{ margin: "20px 20px 20px 0", display: disablebtndelete }} onClick={this.btnDeleteFileClick}>删除附件</Button>
10 <label style={{ float: "left", lineHeight: "0px", color: '#bfbfbf', fontSize: 10 }}>支持扩展名:apk/exe/pdf/xls/doc/ppt等</label>
11 <label style={{ float: "left", lineHeight: "55px" }}>{filenameview}</label>

后端部分

        private static List<FileChunkModel> fileChunkList = new List<FileChunkModel>();
/// <summary>
/// 接收文件片段
/// </summary>
/// <param name="file"></param>
/// <returns></returns>
[HttpPost]
public BackDataModel UploadFileAttachmentChunk(IFormCollection file)
{
try
{
var fileexist = fileChunkList.Where(ff => ff.name == file["name"] && ff.index == file["index"]).ToList();
if (fileexist.Count == 0)
{
using (var stream = file.Files[0].OpenReadStream())
{
using (BinaryReader reader = new BinaryReader(stream))
{
fileChunkList.Add(new FileChunkModel
{
name = file["name"],
index = Convert.ToInt32(file["index"]),
size = file["size"],
formfile = reader.ReadBytes((int)stream.Length)
});
}
}
}
return new BackDataModel { Code = 200, Desc = "" };
}
catch (Exception ex)
{
return new BackDataModel { Code = 201, Desc = "" };
}
} /// <summary>
/// 文件片段组装
/// </summary>
/// <param name="filemodel"></param>
/// <returns></returns>
[HttpPost]
public BackDataModel CombineChunkToFile([FromBody] FileChunkModel filemodel)
{
try
{if (!connectState())
return new BackDataModel() { Code = 201, Desc = $"上传失败,共享文件夹无法访问,请联系管理员确认!" };
List<FileChunkModel> fileChunkModels = fileChunkList.Where(ff => ff.name == filemodel.name).ToList();
if (fileChunkModels.Count == Convert.ToInt32(filemodel.filecount))
{
if (!Directory.Exists($@"\\存储\{filemodel.zhuti}"))
{
Directory.CreateDirectory($@"\\存储\{filemodel.zhuti}");
}
string path = $@"\\存储\{filemodel.zhuti}\{filemodel.filename}";
path = PublicMethod.GetFilePath(path, filemodel); using (FileStream CombineStream = new FileStream(path, FileMode.OpenOrCreate))
{
using (BinaryWriter CombineWriter = new BinaryWriter(CombineStream))
{
                 fileChunkModels = fileChunkModels.OrderBy(ff => ff.index).ToList(); //合并前必须给文件片段按照顺序排列,否则部分文件会被破坏(例如:.apk)
foreach (var filecurr in fileChunkModels)
{
var filechunk = filecurr.formfile;
CombineWriter.Write(filechunk);
fileChunkList.Remove(filecurr);
}
lock (fileChunkList)
{
if (fileChunkList.Count == 0)
{
fileChunkList = null;
fileChunkList=new List<FileChunkModel>();
}
}
return new BackDataModel() { Code = 200, Desc = $"{path}|{path.Split('\\')[path.Split('\\').Length-1]}" };
}
}
}
else
return new BackDataModel() { Code = 201, Desc = "上传失败" };
}
catch (Exception ex)
{
return new BackDataModel() { Code = 201, Desc = "上传失败" };
}
}
/// <summary>
/// 连接远程共享文件夹
/// </summary>
/// <param name="path">远程共享文件夹的路径</param>
/// <param name="userName">用户名</param>
/// <param name="passWord">密码</param>
/// <returns></returns>
private static bool connectState()
{
bool Flag = false;
Process proc = new Process();
try
{
proc.StartInfo.FileName = "cmd.exe";
proc.StartInfo.UseShellExecute = false;
proc.StartInfo.RedirectStandardInput = true;
proc.StartInfo.RedirectStandardOutput = true;
proc.StartInfo.RedirectStandardError = true;
proc.StartInfo.CreateNoWindow = true;
proc.Start();
string dosLine = @"net use \\存储 password /user:username";
proc.StandardInput.WriteLine(dosLine);
proc.StandardInput.WriteLine("exit");
while (!proc.HasExited)
{
proc.WaitForExit(1000);
}
string errormsg = proc.StandardError.ReadToEnd();
proc.StandardError.Close();
if (string.IsNullOrEmpty(errormsg))
{
Flag = true;
}
else
{
throw new Exception(errormsg);
}
}
catch (Exception ex)
{
throw ex;
}
finally
{
proc.Close();
proc.Dispose();
}
return Flag;
}

部署至 IIS 上传大文件异常问题

问题描述:

  在前后端都配置好支持大文件上传后,本地测试没问题,但部署至 IIS 后,上传 30M 以上的文件一直提示失败。

解决方法:

  问题原因: IIS 默认限制了交互最大内容长度(字节)。默认值为:30 000 000。

  所以解决问题的关键就是突破这种限制了。

  其中一种修改步骤如下图:(改成最大 3G)

 注:个人整理,已验证可用,有疑问欢迎指正。

大文件分片上传,后端拼接保存(前端:antd;后端:.Net 5 WebAPI)的更多相关文章

  1. Webuploader 大文件分片上传

    百度Webuploader 大文件分片上传(.net接收)   前阵子要做个大文件上传的功能,找来找去发现Webuploader还不错,关于她的介绍我就不再赘述. 动手前,在园子里找到了一篇不错的分片 ...

  2. java springboot 大文件分片上传处理

    参考自:https://blog.csdn.net/u014150463/article/details/74044467 这里只写后端的代码,基本的思想就是,前端将文件分片,然后每次访问上传接口的时 ...

  3. iOS大文件分片上传和断点续传

    总结一下大文件分片上传和断点续传的问题.因为文件过大(比如1G以上),必须要考虑上传过程网络中断的情况.http的网络请求中本身就已经具备了分片上传功能,当传输的文件比较大时,http协议自动会将文件 ...

  4. js实现大文件分片上传的方法

    借助js的Blob对象FormData对象可以实现大文件分片上传的功能,关于Blob和FormData的具体使用方法可以到如下地址去查看FormData 对象的使用Blob 对象的使用以下是实现代码, ...

  5. Node + js实现大文件分片上传基本原理及实践(一)

    _ 阅读目录 一:什么是分片上传? 二:理解Blob对象中的slice方法对文件进行分割及其他知识点 三. 使用 spark-md5 生成 md5文件 四. 使用koa+js实现大文件分片上传实践 回 ...

  6. nodeJs + js 大文件分片上传

    简单的文件上传 一.准备文件上传的条件: 1.安装nodejs环境 2.安装vue环境 3.验证环境是否安装成功 二.实现上传步骤 1.前端部分使用 vue-cli 脚手架,搭建一个 demo 版本, ...

  7. PHP大文件分片上传的实现方法

    一.前言 在网站开发中,经常会有上传文件的需求,有的文件size太大直接上传,经常会导致上传过程中耗时太久,大量占用带宽资源,因此有了分片上传. 分片上传主要是前端将一个较大的文件分成等分的几片,标识 ...

  8. vue+大文件分片上传

    最近公司在使用vue做工程项目,实现大文件分片上传. 网上找了一天,发现网上很多代码都存在很多问题,最后终于找到了一个符合要求的项目. 工程如下: 对项目的大文件上传功能做出分析,怎么实现大文件分片上 ...

  9. thinkphp+webuploader实现大文件分片上传

    大文件分片上传,简单来说就是把大文件切分为小文件,然后再一个一个的上传,到最后由这些小文件再合并成原来的文件 webuploader下载地址及其文档:http://fex.baidu.com/webu ...

  10. 在React中使用WebUploader实现大文件分片上传的踩坑日记!

    前段时间公司项目有个大文件分片上传的需求,项目是用React写的,大文件分片上传这个功能使用了WebUploader这个组件. 具体交互是: 1. 点击上传文件button后出现弹窗,弹窗内有选择文件 ...

随机推荐

  1. Linux 10 安装JDK

    参考源 https://www.bilibili.com/video/BV187411y7hF?spm_id_from=333.999.0.0 版本 本文章基于 CentOS 7.6 这里使用 rpm ...

  2. apk编辑器测评

    hi你好,我今天要介绍的就是apk编辑器 这里我用的是apk编辑器专业版 APK编辑器 关于 APK 编辑器智友汉化组论坛:bbs.zhiyoo.com修改应用程序名称美化 UI: 更改背景图片删除广 ...

  3. 刷题记录:Codeforces Round #724 (Div. 2)

    Codeforces Round #724 (Div. 2) 20210713.网址:https://codeforces.com/contest/1536. div2明显比div3难多了啊-只做了前 ...

  4. JS/java实现QQ空间自动点赞

    使用方法: 1:进入QQ空间 2:复制下面代码 3:按F12或右键审查元素 进入控制台 也就是console 4:粘贴  回车键  喝口水 5:如果嫌慢的话可以 修改这段代码. window.setI ...

  5. java数组---特点,边界

    数组的四个基本特点 1.其长度是确定的.数组一旦被创建,它的大小就是不可以改变的. 2.其元素必须是相同类型,不允许出现混合类型. 3.数组中的元素可以是任何数据类型,包括基本类型和引用类型. 4.数 ...

  6. 【JavaWeb】学习路径1-背景

    JavaWeb系列也是一个非常庞大的系列,主要分为五个部分讲解: HTML JSP和Servlet CSS的讲解 JavaScrip的讲解 jQuery框架的讲解 学习完上述内容后,就能够基本了解一个 ...

  7. (最简单详细)IronPython下载、安装及简单使用

    说实话,对于我这种小白,在网上找个IronPython找的很费劲,学会操作之后,直接整个随笔,供新手参考.前提是现在你应该有VS了 (1)找到IronPython的网站 很多人肯定就按照习惯搜索,Ir ...

  8. .NET 7 性能改进 -- 至今为止最快的.NET平台

    2022年8月31日 Stephen Toub 发布的关于 .NET 7 性能改进的博客, 核心主题是 .NET 7 速度很快. 这篇博客非常的长,我尝试将它拷贝到Word 里,拷贝的时间都花了几分钟 ...

  9. 第八十四篇:Vue购物车(五) 商品数量的增减

    好家伙, 1.商品数量的增减 我们把商品的数量增减独立出来,写成一个独立的组件Counter <template> <div class="number-container ...

  10. SpringMVC 05: SpringMVC中携带数据的页面跳转

    SpringMVC默认的参数对象 SpringMVC默认的参数对象是指,不用再另行创建,相当于SpringMVC内置对象,可以直接声明并使用 默认的参数对象有:HttpServletRequest,H ...