使用 HTTP 协议上传文件的标准做法是:使用 multipart/form-data
。但有时为了实现简单且要上传的文件不会太大,仍然会采用 application/x-www-form-urlencoded
上传文件,这就需要在上传前对二进制文件进行编码,比如使用 Base64 。
public async Task<IActionResult> SubmitImage(int id, [FromForm(Name = "image")] string image)
{
if (string.IsNullOrWhiteSpace(image)) throw new UserFriendlyException("图片不能为空");
var data = Convert.FromBase64String(image);
//TODO:处理图片
}
以上代码一直工作良好,很久以后接到客户反馈有几张图片一直上传失败,明明选择了图片却还是提示“图片不能为空”。这说明 image 参数没有被正确绑定上。图片的大小为 6MB 左右,这很显然没有突破 IIS 的限制(默认为 30MB),也没有突破 ASP.NET Ccor 对单个请求大小的限制(默认为 30MB)。我特意去查看了 Windows 日志,也没有看到报错信息。
模拟用户的请求,确实在 HTTP 抓包中看到了图片,但是调试器中 image 确实为空。几番搜索下来,我找到了一个名为 FormOptions
的配置类:
https://docs.microsoft.com/zh-cn/dotnet/api/microsoft.aspnetcore.http.features.formoptions?view=aspnetcore-6.0
其中的 ValueLengthLimit
属性有如下定义:
A limit on the length of individual form values. Forms containing values that exceed this limit will throw an InvalidDataException when parsed. Defaults to 4,194,304 bytes, which is approximately 4MB.
也就是说:默认情况下,ASP.NET Core 限制了每个 POST 数据值的长度为 4 MB 大小,超过就会抛出 InvalidDataException
异常。我很可能是遇到了这个限制,但因为并没有抛异常所以不太敢确定。
services.Configure<FormOptions>(options=>{
options.ValueLengthLimit = 209715200;//200MB
});
以上代码将限制提升到了 200MB,经测试问题解决。
使用 Base64 将文件编码后虽然会简化,但同时会导致网络传输内容增大,或者遇到本文所示的异常(默认情况下,multipart/form-data
对单个上传项的限制是 128MB)。如果你使用的是 MVC,也可以直接使用 RequestFormLimitsAttribute
解决该问题:
https://docs.microsoft.com/zh-cn/dotnet/api/microsoft.aspnetcore.mvc.requestformlimitsattribute?view=aspnetcore-6.0