发布 JSON 数据 WebAPI

Posted

技术标签:

【中文标题】发布 JSON 数据 WebAPI【英文标题】:Posting JSON Data WebAPI 【发布时间】:2017-06-05 21:01:02 【问题描述】:

我在将数据发布到托管在 Azure 中的 Web API 服务时遇到了一个奇怪的问题,如果有任何见解,我将不胜感激。

我编写了一个非常基本的 Web API 服务,它有一个通过 Post 方法接收列表的控制器。我正在使用从HttpClientFactory 创建的客户端通过控制台应用程序将数据发布到此 API。

当我在本地调试时一切正常,我已经成功发布了一个包含 100 个元素的列表并将其写入我的本地数据库。如果我将本地 Web API 代码切换为指向我的 Azure 数据库,它仍然可以正常工作,我可以毫无问题地接收 100 个元素并写入 Azure 数据库实例。

当我将 API 服务部署到我的 Azure 帐户并挂钩我的控制台应用程序以向其发布数据时 - 它与包含多达 45 个元素的列表完美配合,并且 PostAsync 等待大约 6 分钟,然后失败内部服务器错误。

所以我的问题是,为什么该服务从能够在大约一秒钟内发布 43 个元素变为失败并发布 44 个元素,但需要 6 分钟?

我应该指出我的列表包含 100 个重复项,因为我正在生成用于测试的数据,因此集合中的特定元素没有任何错误(或不同)。

T 是一个简单的类,有大约 30 个属性,没有子元素,所以我没有发布一个庞大的结构。

我的想法是,这必须是某个地方的大小限制,它在我的本地计算机上没有生效,但在我部署到 Azure 时才生效。我绝不是 Web API 专家,所以我不知道从哪里开始。

一些客户端代码(当 i

List<Foo> results = new List<Foo>();

for (int i = 1; i < 100; i++)

    results.Add(new Foo()  // Populated with data - removed for brevity );


StringContent content = new StringContent(JsonConvert.SerializeObject(results), Encoding.UTF8, "application/json");
HttpResponseMessage postDataResponse = await postClient.PostAsync(myWebApiServiceURL, content);

控制器方法:

[HttpPost]
public List<Foo>Post([FromBody]List<Foo> value)

   return value;

我尝试过的 Web.config 设置无效:

<httpRuntime targetFramework="4.6.1"  maxRequestLength="200000000" requestLengthDiskThreshold="16384" />

<add key="aspnet:MaxJsonDeserializerMembers" value="20000000"/>

我刚刚运行了一个测试,它不适用于 44 个元素内容长度 = 53278

它工作的最大长度是当我的总元素是 43 内容长度 = 48361 时。

注意:我刚刚进行了更多测试,如果我减少一些字符串属性中的数据长度(从而减少每个元素的占用空间),我可以发布更多元素。因此它必须是某处的消息大小限制!

更新 - HMAC 身份验证

好的,原因始终是您未在问题中记录的最意想不到的事情。我在我的 API 上启用了 HMAC 身份验证,当我从控制器中删除该属性时,我可以毫无问题地发布 10000 个元素。一旦我启用它,我就会被限制回 43。

在客户端上,我生成请求内容的 MD5 哈希作为标头签名的一部分,此过程在 Web API 服务的 HMAC 属性中重复。如果我从我的客户端和服务中删除这部分签名,那么我可以发布尽可能多的数据。我在客户端注释掉的代码如下所示:

//Checking if the request contains body, usually will be null with HTTP GET and DELETE
if (request.Content != null)

   byte[] content = await request.Content.ReadAsByteArrayAsync();
   MD5 md5 = MD5.Create();
   //Hashing the request body, any change in request body will result in different hash, we'll incure message integrity
   byte[] requestContentHash = md5.ComputeHash(content);
   requestContentBase64String = Convert.ToBase64String(requestContentHash);

我在服务中注释掉的代码如下:

byte[] hash = await ComputeHash(req.Content);

if (hash != null)

   requestContentBase64String = Convert.ToBase64String(hash);

ComputeHash函数:

private static async Task<byte[]> ComputeHash(HttpContent httpContent)

   using (MD5 md5 = MD5.Create())
   
      byte[] hash = null;
      var content = await httpContent.ReadAsByteArrayAsync();
      if (content.Length != 0)
      
        hash = md5.ComputeHash(content);
      
        return hash;
   

因此,注释掉上述代码后,requestContentBase64String 在客户端和服务器上始终是一个空字符串,因此内容的 MD5 哈希不会用作身份验证签名的一部分。

我现在必须研究这种行为的根本原因。

【问题讨论】:

尝试在 web.config 的 appSettings 下添加 aspnet:MaxJsonDeserializerMembers。检查 json 的长度并将其作为 之类的值 @AliBaig 我用&lt;add key="aspnet:MaxJsonDeserializerMembers" value="20000000"/&gt; 试过了,没有效果。 您是否也尝试过设置 maxRequestLength 大小? @xszaboj 是的,请参阅编辑 您的 Azure 站点上是否有任何日志记录可以告诉您“内部服务器错误”是什么问题?至少检查您是否在控制器中收到请求,或者在此之前它是否失败。这可能是由无效数据(即使它在本地工作)、从 Web 应用程序到 Azure DB 的连接错误造成的...... 【参考方案1】:

https://blogs.msdn.microsoft.com/azureossds/2016/06/15/uploading-large-files-to-azure-web-apps/

检查 Azure 的最大帖子大小。根据您的配置,这可能是问题所在。要么更改配置,要么考虑将帖子大小减小为更小的块。

【讨论】:

感谢您的建议,但我不会发布那么多数据(小于 1 兆字节),如果我删除 HMAC 身份验证,我可以毫无问题地通过 Azure 发布更大的卷。问题出在我对身份验证属性的实现中。我还没有花足够的时间调查找出根本原因。

以上是关于发布 JSON 数据 WebAPI的主要内容,如果未能解决你的问题,请参考以下文章

webAPI

WebAPI学习笔记

webAPI第一弹---JS

webAPI第一弹---JS

浅谈web api和Webservice

javaScript从入门到精通2.md