NetCore3.0 文件上传与大文件上传的限制
NetCore文件上传两种方式
NetCore官方给出的两种文件上传方式分别为“缓冲”、“流式”。我简单的说说两种的区别,
1.缓冲:通过模型绑定先把整个文件保存到内存,然后我们通过IFormFile得到stream,优点是效率高,缺点对内存要求大。文件不宜过大。
2.流式处理:直接读取请求体装载后的Section 对应的stream 直接操作strem即可。无需把整个请求体读入内存,
以下为官方微软说法
缓冲
整个文件读入 IFormFile,它是文件的 C# 表示形式,用于处理或保存文件。 文件上传所用的资源(磁盘、内存)取决于并发文件上传的数量和大小。 如果应用尝试缓冲过多上传,站点就会在内存或磁盘空间不足时崩溃。 如果文件上传的大小或频率会消耗应用资源,请使用流式传输。
流式处理
从多部分请求收到文件,然后应用直接处理或保存它。 流式传输无法显著提高性能。 流式传输可降低上传文件时对内存或磁盘空间的需求。
文件大小限制
说起大小限制,我们得从两方面入手,1应用服务器Kestrel 2.应用程序(我们的netcore程序),
1.应用服务器Kestre设置
应用服务器Kestrel对我们的限制主要是对整个请求体大小的限制通过如下配置可以进行设置(Program -> CreateHostBuilder),超出设置范围会报 BadHttpRequestException: Request body too large 异常信息
public static IHostBuilder CreateHostBuilder(string[] args) =>
Host.CreateDefaultBuilder(args)
.ConfigureWebHostDefaults(webBuilder =>
{
webBuilder.ConfigureKestrel((context, options) =>
{
//设置应用服务器Kestrel请求体最大为50MB
options.Limits.MaxRequestBodySize = ;
});
webBuilder.UseStartup<Startup>();
});
2.应用程序设置
应用程序设置 (Startup-> ConfigureServices) 超出设置范围会报InvalidDataException 异常信息
services.Configure<FormOptions>(options =>
{
options.MultipartBodyLengthLimit = long.MaxValue;
});
通过设置即重置文件上传的大小限制。
源码分析
这里我主要说一下 MultipartBodyLengthLimit 这个参数他主要限制我们使用“缓冲”形式上传文件时每个的长度。为什么说是缓冲形式中,是因为我们缓冲形式在读取上传文件用的帮助类为 MultipartReaderStream 类下的 Read 方法,此方法在每读取一次后会更新下读入的总byte数量,当超过此数量时会抛出 throw new InvalidDataException($"Multipart body length limit {LengthLimit.GetValueOrDefault()} exceeded."); 主要体现在 UpdatePosition 方法对 _observedLength 的判断
以下为 MultipartReaderStream 类两个方法的源代码,为方便阅读,我已精简掉部分代码
Read
public override int Read(byte[] buffer, int offset, int count)
{ var bufferedData = _innerStream.BufferedData;
int read;
read = _innerStream.Read(buffer, offset, Math.Min(count, bufferedData.Count));
return UpdatePosition(read);
}
UpdatePosition
private int UpdatePosition(int read)
{
_position += read;
if (_observedLength < _position)
{
_observedLength = _position;
if (LengthLimit.HasValue && _observedLength > LengthLimit.GetValueOrDefault())
{
throw new InvalidDataException($"Multipart body length limit {LengthLimit.GetValueOrDefault()} exceeded.");
}
}
return read;
}
通过代码我们可以看到 当你做了 MultipartBodyLengthLimit 的限制后,在每次读取后会累计读取的总量,当读取总量超出
MultipartBodyLengthLimit 设定值会抛出 InvalidDataException 异常,
最终我的文件上传Controller如下
需要注意的是我们创建 MultipartReader 时并未设置 BodyLengthLimit (这参数会传给 MultipartReaderStream.LengthLimit )也就是我们最终的限制,这里我未设置值也就无限制,可以通过 UpdatePosition 方法体现出来
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.WebUtilities;
using Microsoft.Net.Http.Headers;
using System.IO;
using System.Threading.Tasks; namespace BigFilesUpload.Controllers
{
[Route("api/[controller]")]
public class FileController : Controller
{
private readonly string _targetFilePath = "C:\\files\\TempDir"; /// <summary>
/// 流式文件上传
/// </summary>
/// <returns></returns>
[HttpPost("UploadingStream")]
public async Task<IActionResult> UploadingStream()
{ //获取boundary
var boundary = HeaderUtilities.RemoveQuotes(MediaTypeHeaderValue.Parse(Request.ContentType).Boundary).Value;
//得到reader
var reader = new MultipartReader(boundary, HttpContext.Request.Body);
//{ BodyLengthLimit = 2000 };//
var section = await reader.ReadNextSectionAsync(); //读取section
while (section != null)
{
var hasContentDispositionHeader = ContentDispositionHeaderValue.TryParse(section.ContentDisposition, out var contentDisposition);
if (hasContentDispositionHeader)
{
var trustedFileNameForFileStorage = Path.GetRandomFileName();
await WriteFileAsync(section.Body, Path.Combine(_targetFilePath, trustedFileNameForFileStorage));
}
section = await reader.ReadNextSectionAsync();
}
return Created(nameof(FileController), null);
} /// <summary>
/// 缓存式文件上传
/// </summary>
/// <param name=""></param>
/// <returns></returns>
[HttpPost("UploadingFormFile")]
public async Task<IActionResult> UploadingFormFile(IFormFile file)
{
using (var stream = file.OpenReadStream())
{
var trustedFileNameForFileStorage = Path.GetRandomFileName();
await WriteFileAsync(stream, Path.Combine(_targetFilePath, trustedFileNameForFileStorage));
}
return Created(nameof(FileController), null);
} /// <summary>
/// 写文件导到磁盘
/// </summary>
/// <param name="stream">流</param>
/// <param name="path">文件保存路径</param>
/// <returns></returns>
public static async Task<int> WriteFileAsync(System.IO.Stream stream, string path)
{
const int FILE_WRITE_SIZE = ;//写出缓冲区大小
int writeCount = ;
using (FileStream fileStream = new FileStream(path, FileMode.Create, FileAccess.Write, FileShare.Write, FILE_WRITE_SIZE, true))
{
byte[] byteArr = new byte[FILE_WRITE_SIZE];
int readCount = ;
while ((readCount = await stream.ReadAsync(byteArr, , byteArr.Length)) > )
{
await fileStream.WriteAsync(byteArr, , readCount);
writeCount += readCount;
}
}
return writeCount;
} }
}
总结:
如果你部署 在iis上或者Nginx 等其他应用服务器 也是需要注意的事情,因为他们本身也有对请求体的限制,还有值得注意的就是我们在创建文件流对象时 缓冲区的大小尽量不要超过netcore大对象的限制。这样在并发高的时候很容易触发二代GC的回收.
NetCore3.0 文件上传与大文件上传的限制的更多相关文章
- 框架基础:ajax设计方案(三)--- 集成ajax上传技术 大文件/超大文件前端切割上传,后端进行重组
马上要过年了,哎,回家的心情也特别的激烈.有钱没钱,回家过年,家永远是舔舐伤口最好的地方.新的一年继续加油努力. 上次做了前端的ajax的上传文件技术,支持单文件,多文件上传,并对文件的格式和大小进行 ...
- 前端通信:ajax设计方案(四)--- 集成ajax上传技术 大文件/超大文件前端切割上传,后端进行重组
马上要过年了,哎,回家的心情也特别的激烈.有钱没钱,回家过年,家永远是舔舐伤口最好的地方.新的一年继续加油努力. 上次做了前端的ajax的上传文件技术,支持单文件,多文件上传,并对文件的格式和大小进行 ...
- Loadrunner上传文件解决办法(大文件)
Loadrunner上传文件解决办法(大文件) 最近再做一个跟海量存储相关的项目测试,需要通过LR模拟用户大量上传和下载文件,请求是Rest或Soap,同时还要模拟多种大小尺寸不一的文件 通常情况下, ...
- SC || 解决在git中上传过大文件的问题(如何将提交过的彻底删除
就在我在ddl前续命的时候……不知道怎么想不开,把v2的压力测试的日志(500多M)也往github上传 之前听说过好多因为传了大文件的锅…… 我竟然还想不开的往上传…… 真实又傻又蠢又自闭(T T ...
- Python组织文件 实践:查找大文件、 用Mb、kb显示文件尺寸 、计算程序运行时间
这个小程序很简单原本没有记录下来的必要,但在编写过程中又让我学到了一些新的知识,并且遇到了一些不能解决的问题,然后,然后就很有必要记录一下. 这个程序的关键是获取文件大小,本来用 os.path.ge ...
- 转:Loadrunner上传文件解决办法(大文件)
最近再做一个跟海量存储相关的项目测试,需要通过LR模拟用户大量上传和下载文件,请求是Rest或Soap,同时还要模拟多种大小尺寸不一的文件 通常情况下,都是使用简单的post协议即可: 方法一: we ...
- B/S结构下上传下载大文件(1G以上)的解决方案
以ASP.NET Core WebAPI 作后端 API ,用 Vue 构建前端页面,用 Axios 从前端访问后端 API ,包括文件的上传和下载. 准备文件上传的API #region 文件上传 ...
- ASP.NET 使用ajaxfileupload.js插件出现上传较大文件失败的解决方法(ajaxfileupload.js第一弹)
在写这篇的时候本来想把标题直接写成报错的提示,如下: “SecurityError:Blocked a frame with origin "http://localhost:55080&q ...
- ASP.NET 使用ajaxupload.js插件出现上传较大文件失败的解决方法
在网上下载了一个ajaxupload.js插件,用于无刷新上传图片使的,然后就按照demo的例子去运行了一下,上传啊什么的都OK,但是正好上传的示例图片有一个比较大的,4M,5M的样子,然后上传就会报 ...
- asp.net 文件上传,大文件上传。
新建一个asp.net页面,在工具栏里拖入 FileUpload 上传控件.一个按钮 Button ! ! ! 进入Button事件 //----------------------- ...
随机推荐
- C++ Web框架::cintara
1.Cinatra是由C++开源社区purecpp发起的一个开源项目,是一个现代C++写的Web框架,旨在给用户提供一个易用.灵活和高性能的Web框架,让用户能完全专注于核心逻辑而无需关注http细节 ...
- 技术分享:Dapr,让开发人员更轻松地构建微服务应用
最近一直在学习微服务相关的技术.微服务架构已成为构建云原生应用程序的标准,并且可以预见,到2022年,将有90%的新应用程序采用微服务架构.微服务架构提供了令人信服的好处,包括可伸缩性,松散的服务耦合 ...
- shell传递参数(三)
$n:n代表一个数字,指执行脚本的第n个参数.特别地,$0指执行的文件名 [root@ipha-dev71- exercise_shell]# cat test.sh #!/bin/bash echo ...
- 22.Linux定时任务
1.计划任务时间管理 参数 含义 -e 编辑定时任务 -l 查看定时任务 -r 删除定时任务 -u 指定其他用户 \* 表示任意的(分.时.日.月.周)时间都执行 \- 表示一个时间范围段, 如5-7 ...
- Linux必备工具与软件包
yum -y update(所有都升级和改变) 升级所有包,系统版本和内核,改变软件设置和系统设置 ----------------------------------------------- yu ...
- java读取存在src目录下和存在同级目录下的配置文件
如果我有个文件存在src下一级的地方和存在src同级的目录应该怎么用相对路径去获取如图: 一.如果存在src同级的地方应该是InputStream in = new BufferedInputStre ...
- JVM 启动调优总结
启动命令 格式: java -jar 命令行参数 jar包路径 .示例如下 java -Dfile.encoding=utf-8 -jar -XX:MetaspaceSize=128m -XX:Max ...
- linux 基本操作--笔记
linux 基本操作: pwd 显示当前目录 ll 用于查看文件和目录,即list,其参数比较多 -l 列出数据串,包含文件的属性和权限数据等 -a 列出全部文件,包含隐藏文件 -d 仅列出目录本身, ...
- ESP8266 打造一款物联网产品---搭建环境编译及烧录
一 前记 作为一个在wifi领域耕耘了多年的人,以前一直在外企和大公司做芯片,没有怎么使用过国内的芯片公司做出来的芯片.最近正好有一个项目需要用到一款低成本的wifi芯片,找来找去,发现乐鑫的最适合. ...
- 在k8s上安装Jenkins及常见问题
持续集成和部署是DevOps的重要组成部分,Jenkins是一款非常流行的持续集成和部署工具,最近试验了一下Jenkins,发现它是我一段时间以来用过的工具中最复杂的.一个可能的原因是它需要与各种其它 ...