前言

对于普通业务场景而言,直接用 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. 从 Airflow 到 Apache DolphinScheduler,有赞大数据开发平台的调度系统演进

    点击上方 蓝字关注我们 作者 | 宋哲琦 ✎ 编 者 按 在不久前的 Apache  DolphinScheduler Meetup 2021 上,有赞大数据开发平台负责人 宋哲琦 带来了平台调度系统 ...

  2. ApacheCon 2020 参会指南

    每年一度的 Apache 北美大会因为疫情的原因转到线上来举行了, 这次会议的主题是 ApacheCon@Home, 也就是说借助网络我们可以足不出户就可以参加 Apache 大会了.今年的会议为了针 ...

  3. Java八股文纯享版——篇①:Java基础

    注: 1.笔记为个人归纳整理,尽力保证准确性,如有错误,恳请指正 2.写文不易,转载请注明出处 3.本文首发地址 https://blog.leapmie.com/archives/b8fe0da9/ ...

  4. RabbitMQ 入门系列:3、基础编码:官方SDK的引用、链接创建、单例改造、发送消息、接收消息。

    系列目录 RabbitMQ 入门系列:1.MQ的应用场景的选择与RabbitMQ安装. RabbitMQ 入门系列:2.基础含义:链接.通道.队列.交换机. RabbitMQ 入门系列:3.基础含义: ...

  5. LOJ6077「2017 山东一轮集训 Day7」逆序对 (生成函数+多项式exp?朴素DP!)

    题面 给定 n , k n,k n,k ,求长度为 n n n 逆序对个数为 k k k 的排列个数,对 1 e 9 + 7 \rm1e9+7 1e9+7 取模. 1 ≤ n , k ≤ 100   ...

  6. Sentinel控制台1.8.3修改源码,修改配置后推送到Nacos

    目录 1. 接着上一篇 2. 思路 3. 下载Sentinel源码 4. 看Gateway里面读取的配置信息 5. 修改Sentinel控制台源码 6. 熔断规则测试 7. 限流规则测试 8. 打包使 ...

  7. 关于DOS命令窗口的一点基本知识

    1.DOS命令窗口又可称为CMD窗口.shell.终端. 2.常用的DOS命令: -硬盘分区名+: :进入到该硬盘分区(注意是英文冒号哦) -cd+目录名:进入到指定(该)目录 -dir:列出当前目录 ...

  8. 富莱尔ERP

    微型版本 按年付费模式 980包含5个用户,后续每增加一个用户加298元. 适合创业型企业,想尝试用下ERP软件解决打送货单问题,客户自动生成账单,自动统计业务员每月业绩功能. 试用账号:wxadmi ...

  9. 一步步搞懂MySQL元数据锁(MDL)

    某日,路上收到用户咨询,为了清除空间,想删除某200多G大表数据,且已经确认此表不再有业务访问,于是执行了一条命令'delete from bigtable',但好长时间也没删完,经过咨询后,获知dr ...

  10. 第一个Java代码的编写 :HelloWorld代码的编写

    HelloWorld代码的编写 创建一个新的文件夹,通过Notepad++编写第一个Java程序 , 文件名为"Hello.java" 在文件中编写,如下代码: public cl ...