提到網頁功能一定會有下載檔案/上傳檔案
需求,這邊整理會用到方法與遇到上傳檔案問題。
下載檔案
1
2
3
4
5
6
7
8
9
10
11
12
13
|
public IActionResult Get([FromQuery] GetFileDownloadRequest request)
{
FileTypeEnum fileType = request.ReqFileType;
string filePath = "";
... getFilePath
if (string.IsNullOrEmpty(filePath))
{
return NotFound();
}
string fileName = Path.GetFileName(filePath);
return PhysicalFile(filePath, "application/octet-stream",fileDownloadName: fileName);
}
|
下載依照 Content-Type 設定metadata
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
|
[HttpGet("[action]")]
public async Task<IActionResult> GetFile(string id)
{
var dir = "GetOrBuildYourDirectoryString";
var fileName = "GetYourFileName";
var mimeType = GetMimeType(fileName);
var path = Path.Combine(dir, fileName);
return PhysicalFile(path, mimeType, version.FileName);
}
public string GetMimeType(string fileName)
{
var provider = new FileExtensionContentTypeProvider();
string contentType;
if (!provider.TryGetContentType(fileName, out contentType))
{
contentType = "application/octet-stream";
}
return contentType;
}
|
參考:在TypeScript和ASP.NET Core中处理文件上传和受保护的下载_寒冰屋的博客-CSDN博客
可接續下載方法
1
2
3
4
5
6
7
8
9
|
[HttpGet("[action]")]
public async Task<IActionResult> GetFile(string id)
{
string filePath = "xxx";
string fileName = Path.GetFileName(filePath);
new FileExtensionContentTypeProvider().TryGetContentType(fileName, out string contentType);
contentType ??= "application/octet-stream";
return PhysicalFile(filePath, contentType, fileDownloadName: fileName, enableRangeProcessing: true);
}
|
主要是 enableRangeProcessing
設定為 true 就能做到,想當初 PHP 實作這個方法看到吐。
相關別的程式作法:
參考
上傳檔案
推薦看下官方文件,裡面有滿多東西
推薦看下官方文件,裡面有滿多東西
推薦看下官方文件,裡面有滿多東西
在 ASP.NET Core 中上傳檔案 | Microsoft Docs
這邊先紀錄單純上傳方法,可能沒官方有做一些嚴謹判斷,有空再來開一篇記錄。(有空的話😜)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
|
// 自行注入
private readonly IConfiguration _configuration;
private readonly IWebHostEnvironment _env;
[HttpPost]
[Route("[controller]")]
public IActionResult Post([FromForm]Request request){
...
UploadFile(...,request.UploadFile);
...
}
private void UploadFile(string paramPathName, IFormFile uploadFile)
{
string filepath = ProcessUploadedFile(paramPathName, "paramFileTypePath", uploadFile);
...
}
private string ProcessUploadedFile(string paramPathName, string directory,IFormFile formFile)
{
string uniqueFileName = null;
if (string.IsNullOrWhiteSpace(_env.WebRootPath))
{
_env.WebRootPath = System.IO.Path.Combine(Directory.GetCurrentDirectory(), "wwwroot");
}
string datePath = DateTime.Now.ToString("yyyyMMdd");
string rootPath = _configuration["UploadFilePath"] ?? _env.WebRootPath;
string uploadsFolder = Path.Combine(rootPath, "upload", paramPathName, directory, datePath);
if (formFile != null)
{
Directory.CreateDirectory(uploadsFolder);
uniqueFileName = Guid.NewGuid().ToString() + "_" + formFile.FileName;
string filePath = Path.Combine(uploadsFolder, uniqueFileName);
using var fileStream = new FileStream(filePath, FileMode.Create);
formFile.CopyTo(fileStream);
}
return Path.Combine(uploadsFolder, uniqueFileName);
}
}
|
上傳限制調整
主要參考這兩個網站整理資訊。
設定 IIS 上傳限制
IIS 的 web.config 設定
1
2
3
4
5
6
7
8
|
<!--//上传文件大小限制IIS设置 256M -->
<system.webServer>
<security>
<requestFiltering>
<requestLimits maxAllowedContentLength="268435456" />
</requestFiltering>
</security>
</system.webServer>
|
這段程式碼的關鍵:requestLimits maxAllowedContentLength=“209715200” 。這句話的意思就是把允許上傳的最大檔案設定為256M。這個值,你們可以根據自己項目的需要實際設定。這裡,我們先暫時設定成256M。
這邊要我們用算的可能很不方便,我這邊有找到這個網站可以算出。
奇怪怎麼沒有找到前端版本
- 這邊 Kestrel 也要設定上限(MaxRequestBodySize)
預設的要求本文大小上限為 30,000,000 個位元組,大約是 28.6 MB。
1
2
3
4
5
6
7
8
9
10
11
|
//上傳文件大小限制Kestrel設置
services.Configure<KestrelServerOptions>(options =>
{
// Set the limit to 256 MB
options.Limits.MaxRequestBodySize = 268435456;
});
//上傳文件大小限制IIS設置(下面這段可以不用複製)
services.Configure<IISServerOptions>(options =>
{
options.MaxRequestBodySize = long.Parse(Configuration.GetSection("Kestrel").Value);
});
|
但是沒設定的話,會出現Request body too large 錯誤
。
IISServerOptions
我看這段很奇怪,使用上去沒有成功。後來看到:
獲取或設置 HttpRequest 的最大請求正文大小。請注意,IIS 本身俱有限制 maxAllowedContentLength,它將在 IISServerOptions 中設置的 MaxRequestBodySize 之前處理。更改 MaxRequestBodySize 不會影響 maxAllowedContentLength。要增加 maxAllowedContentLength,請在 web.config 中添加一個條目以將 maxAllowedContentLength 設置為更高的值。有關詳細信息,請參閱配置。
參考: AspNetCore.Docs/in-process-hosting.md at main · dotnet/AspNetCore.Docs
Request body too large 錯誤
Post的body大概超過30m就會報這個錯誤,完整的錯誤是Microsoft.AspNetCore.Server.Kestrel.Core.BadHttpRequestException: Request body too large
解決的方法有二種,一種是在請求的函數前加Attribute
1
2
3
4
5
|
[HttpPost("upload")]
[RequestSizeLimit(100_000_000)] //最大100m左右
//[DisableRequestSizeLimit] //或者取消大小的限制
public async Task<string> UploadFiles(ModelTest test)
{
|
還有一種方法是全域增加請求body的大小或者不限body的大小。
1
2
3
4
5
6
7
8
9
10
11
12
13
|
public static IWebHost BuildWebHost(string[] args)
{
var config = new ConfigurationBuilder()
.AddCommandLine(args)
.Build();
return WebHost.CreateDefaultBuilder(args).UseConfiguration(config)
.UseStartup<Startup>().UseKestrel(options =>
{
//所有controller都不限制post的body大小
options.Limits.MaxRequestBodySize = null;
})
.Build();
}
|
Multipart body length limit 134217728 exceeded錯誤
Post的body大概超過100多M會碰到這個錯誤,完整的錯誤資訊是 System.IO.InvalidDataException: Multipart body length limit 134217728 exceeded.
。
整體設定方法
解決的方法是在 startup.cs 新增程式碼:
1
2
3
4
5
6
7
8
9
|
public void ConfigureServices(IServiceCollection services)
{
services.AddMvc();
//解決Multipart body length limit 134217728 exceeded
services.Configure<FormOptions>(x =>
{
x.ValueLengthLimit = int.MaxValue;
x.MultipartBodyLengthLimit = int.MaxValue; // In case of multipart
});
|
RequestFormLimitsAttribute 用來設定 MultipartBodyLengthLimit 單一頁面或動作的 。
單一頁面設定放法
這段程式碼的關鍵:requestLimits maxAllowedContentLength=“209715200” 。這句話的意思就是把允許上傳的最大檔案設定為200M。這個值,你們可以根據自己項目的需要實際設定。這裡,我們先暫時設定成200M。這時,我們再跑一下項目,會發現404錯誤已經不見了,取而代之的是另一種錯誤:
這段錯誤程式碼的意思是表單上傳的檔案長度超過了134217727KB,要解決這個問題,我們只有在Home控製器裡的Upload方法前加入如下屬性聲明:[RequestFormLimits(MultipartBodyLengthLimit = 209715200)]
1
2
3
4
5
6
7
8
9
10
|
[HttpPost]
[RequestFormLimits(MultipartBodyLengthLimit = 209715200)]
public IActionResult Upload(IFormFile file,
[FromServices] IHostingEnvironment env)
{
...
...
}
|
基本上使用 IIS 和 Kestrel 都需要設定的。
Nginx 限制上傳大小的錯誤
通過Nginx連接埠對應,請求會先經過Nginx,也需要額外再設定一個參數client_max_body_size,否則上傳大檔案也會有問題
1
2
3
4
5
|
location ^~ /sample2/ {
rewrite ^/sample2/(.*)$ /$1 break;
proxy_pass http://localhost:5556;
client_max_body_size 300m; #最大接受300m檔案以內的
}
|
Kestrel 中的解決方案
如果你的程序時運行在 Kestrel 上,你可以在應用程式等級(整個系統),或者是 Action 等級控制上傳檔案的大小。
你如果要在 Action 等級控制上傳檔案的大小,你需要設定兩個屬性[RequestSizeLimit] 和 [RequestFormLimits].
[RequestSizeLimit]屬性設定請求的最大長度(以位元組為單位),而[RequestFormLimits]設定多部分正文長度的最大長度。
1
2
3
4
5
6
7
8
9
|
[HttpPost]
[RequestFormLimits(MultipartBodyLengthLimit = 209715200)]
[RequestSizeLimit(209715200)]
public IActionResult Upload(IFormFile file,
[FromServices] IHostingEnvironment env)
{
...
...
}
|
想要全域設定
1
2
3
4
5
6
7
8
|
public static IWebHostBuilder CreateWebHostBuilder
(string[] args) =>
WebHost.CreateDefaultBuilder(args)
.UseStartup<Startup>()
.UseKestrel(options =>
{
options.Limits.MaxRequestBodySize = 209715200;
});
|
也需要設定
1
2
3
4
5
6
7
8
|
public void ConfigureServices(IServiceCollection services)
{
services.AddMvc();
services.Configure<FormOptions>(x =>
{
x.MultipartBodyLengthLimit = 209715200;
});
}
|
設定總結
光一個上傳檔案有這麼多選項,這邊做個整理,剛開始看也不知道差在哪邊。
用 IIS 通常會要設定 XML requestLimits maxAllowedContentLength,相關 MultipartBodyLengthLimit
也要在程式設定。
用 Kestrel 一樣也要設定這些東西(MaxRequestBodySize
、MaxRequestBodySize
),兩個都家都不會有影響。
其他相關文件(整理前參考)
Serving video file / stream from ASP Net Core 6 Minimal API - Microsoft Q&A
net core api上传下载大文件 413、400错误 IIS服务器 - wskxy - 博客园
1
2
|
[RequestFormLimits(MultipartBodyLengthLimit = 209715200)]
[HttpPost("Up/{id}")]
|
或
1
2
3
4
|
services.Configure<IISServerOptions>(options =>
{
options.MaxRequestBodySize = 209715200;
});
|
參考:.net Core 解决Form value count limit 1024 exceeded. (文件上传过大) - Pursue - 博客园
怎流一個上傳檔案容量限制就有這麼多種設定方法。
彩蛋
ASP.NET Core 一行程式碼搞定檔案上傳-知識星球
環境變數