不常见的一个问题,起因是同事使用 .NET Framework 4.6.1 构建的 ASP.NET WebAPI 站点服务的某个 POST 接口需要接收长度接近 7,000,000 的 JSON 字符串,大约 **13.3 MB**。客户端请求成功,服务端也没有报错,但是实际解析出的传输是 null
。
[POST]
[Route("/api/demo/exec")]
public IHttpActionResult Execute([FromBody] InParam param)
{
// ...
}
问题排查
在看到上述代码后,首先想到的是 [FromBody] 属性,它标识了该入参来自 Http Request Body,那会不会是 ContentType 设置不正确?
检查 ContentType
遂联系其要来构造 HTTP Request 的相关代码,大致如下所示:
private static T Post<T>(string action, object param)
{
var json = JsonConver.SerializeObject(param);
HttpContent httpContent = new StringContent(json);
HttpContent.Headers.ContentType = new MediaTypeHeaderValue("application/json");
HttpContent.Headers.ContentType.CharSet = "utf-8";
//...
}
可以看到,使用 contentType: application/json 来指名使用 JSON 来发送复杂数据应该是完全没问题的。
那么…会不会是长度超出了上限?我们知道 Web 服务出于自身的保护(通常是由 IIS、Nginx 等负载提供),都会限制数据传输的大小,特别是接收的数据。
检查 web.config 中的可配置项
通过上网检索,我们很快可以找到一些相关的配置项:HttpRuntimeSection.MaxRequestLength、aspnet:MaxJsonDeserializerMembers)、maxAllowedContentLength。
MaxRequestLength
官方给出的说明是:
MaxRequestLength 属性指定输入流的缓冲阈值的限制。 例如,此限制可用于防止拒绝服务攻击,这些攻击由向服务器发送大型文件的用户造成。 请求的最大大小(以千字节为单位)。 默认大小为 4096 KB (4 MB)。
问题找到了,此配置项的默认大小仅为 4 MB,远远低于我们所需要的 13.3 MB。
MaxJsonDeserializerMembers
官方给出的说明是:
Specifies the limit of the maximum number of items that can be present in any dictionary deserialized by the JavaScriptSerializer type. Default value: 1000
可以看出,此项配置所限制的是反序列化的字段长度。我们要传输的数据模型中所定义的字段远远不足默认配置的 1000 个,因此此项无需修改。
maxAllowedContentLength
官方给出的说明是:
Optional uint attribute. Specifies the maximum length of content in a request, in bytes. The default value is 30,000,000, which is approximately 28.6MB.
也就是说,默认可接受的内容大小为 28.6 MB,满足我们传输的内容大小 13.3 MB,因此此项无需修改。
结论
显然,按目前我们的需求,只需要配置 MaxRequestLength 一项即可。
解决方案
打开 web.config 文件,添加或修改以下配置项:
<system.web>
<!-- targetFramework 属性是你的 .NET Framework 版本-->
<!-- maxRequestLength 请按实际需求设置(KB),此处 2147483647 为可设置的最大值-->
<httpRuntime targetFramework="4.6.1" maxRequestLength="2147483647" />
</system.web>