Azure连接设置中的Web API因大量请求而失败

问题描述 投票:-3回答:2

我在AspNetCore中有一个WebApi,它部署在Azure App服务上。 WebApi只能用于发布对象数组。该对象包含许多属性(100+)和3个对象数组。 (它代表一座建筑物)。对象数组每个可以包含300多个对象。

当我在Visual Studio 2017(15.4.1)中调试时,api工作正常并接受所有请求。部署到Azure时,它接受大多数请求。但是有一些消失在虚空之中。我的意思是没有任何回应。出错的请求在其中一个数组中有很多对象。通过将对象数量减少到一定数量,接受请求。如上所述,在visual studio中,所有请求都被接受。数据发送是可靠的。

我创建了一个测试控制器,具有相同的接口,但没有逻辑,只响应“成功”!在此接口上,请求也会失败(相同的行为)。两个控制器使用Newtonsoft(10.0.3)进行反序列化。

什么可能导致这些请求的行为差异?

控制器的代码:

public class TestController : Controller
{       
    [HttpPost]
    [RequireHttps]
    public IActionResult Post([FromBody] Buildings Buildings)
    {
        enumActionResult status = enumActionResult.success;
        try
        {   
            if (Buildings == null)
                throw new Exception("No valid buildings posted!");

            if (Buildings.items == null)
                throw new Exception("No valid building items posted!");

            if (Buildings.items.Count == 0)
                throw new Exception("Zero building items posted!");


            return Json(new response() { status = status.ToString(), Buildings = list
        }

        catch (Exception ex)
        {
            return Json(new ErrorResponseFormat() { message = ex.Message, status = enumActionResult.error, data = new ErrorResponse(ex) });
        }
    }
}

更新(2017-12-19):问题仍然存在,但缩小到SSL。我创建了一个新的控制器,它只返回请求:

 public class EchoController : Controller
    {
        [HttpPost]           
        public IActionResult Post()
        {
            return new FileStreamResult(Request.Body, Request.ContentType);
        }
    }

如果我在URL失败的情况下使用https发出请求,并且我在http URL上触发了完全相同的请求,那么它就是成功的。这与我从调试器获得的行为相同,因为它仅使用http。因此,不是调试器和天蓝云环境之间的差异,问题似乎是http与https。

与此同时,我在配置中实现(由Bruce Chen建议):

    <system.webServer>
        <security>
          <requestFiltering>
            <!-- Measured in Bytes -->
            <requestLimits maxAllowedContentLength="4000000000" maxQueryString="100000000"/>        
            <!-- 1 GB, Byte in size, up to 2GB-->
          </requestFiltering>   
         <access sslFlags="Ssl, SslRequireCert"/>        
        </security>
      </system.webServer>

并升级到.NET 4.6.2。此时仍然没有解决方案,但问题似乎缩小了。

更新(20-12-2017):我发现了以下有趣的事情:当我向(https)api发送“大”请求时,它会丢失。但是当它有一个小请求时,两个请求都被接受。所以看起来大型请求的连接设置失败了。

webapi使用自定义域,https和IP白名单。客户端需要使用客户端证书进行身份验证。完整的Webapi配置(是的,我删除了以前的requestLimits条目):

    configuration>
  <connectionStrings>
    ...
  </connectionStrings>
  <system.webServer>
    <security>      
       <access sslFlags="Ssl, SslRequireCert"/>   
    </security>
  </system.webServer>
   <runtime>
      <gcServer enabled="true"/>
   </runtime> 
</configuration>

客户是邮递员,使用证书。有什么想法吗?

c# azure ssl asp.net-web-api asp.net-core-webapi
2个回答
0
投票

根据我的理解,您的请求可能会达到IIS限制。由于requestLimits的maxAllowedContentLength属性描述如下:

指定请求中内容的最大长度(以字节为单位)。

默认值为30000000。

我假设您可以按如下方式增加maxAllowedContentLength:

<security>
  <requestFiltering>
    <!-- Measured in Bytes -->
    <requestLimits maxAllowedContentLength="1073741824" />  <!-- 1 GB, Byte in size, up to 2GB-->
  </requestFiltering>
</security>

我建议你检查你的请求体型,并尝试增加maxAllowedContentLength来缩小这个问题。此外,我发现一个issue谈论ASP.NET Core 2.0.0中的请求大小限制。此外,这是一个类似的问题,你可以参考here


0
投票

终于在msdn博客中找到了答案。

https://blogs.msdn.microsoft.com/waws/2017/04/03/posting-a-large-file-can-fail-if-you-enable-client-certificates/

我们的解决方案是第一个选择,因为客户端不是.NET应用程序。感觉像作弊,但它的作用。

(下面我复制了链接中的文本,以便保存,因为它很难找到):

概观

如果您需要客户端证书并POST或PUT大量数据,您的请求可能会失败。这已经成为IIS存在至少10年的问题(这现在适用于Windows平台上的Azure应用服务,因为它使用IIS)。关于此的信息不多,所以这篇博客应该有助于澄清这个问题。解决方案非常简单!

问题

HTTPS(TCP)的基础协议将大数据包分解为多个帧。通常,这不是应用程序的问题,对客户端和服务器都是透明的。某些需要客户端证书的应用程序因此而遇到问题...当初始数据被推送到多个帧并且IIS服务器在继续之前需要客户端证书时。当数据开始从客户端流向服务器(在服务器Hello的最初SSL握手之后)并且发送第一个数据包时,您实际上可以在网络跟踪中看到这一点。服务器回复是客户端证书请求的开始,然后来自客户端的下一个数据包包含更多数据。此时服务器抛出错误,因为它期望线路上的下一个数据是客户端证书。对于较小的数据包,这不会发生,因为对POST或PUT的整个请求已经完成,服务器接下来的事情是客户端证书握手,而不是来自PUSH或PUT的附加数据

解析度

要解决此问题,您只需使用以下两种技术之一:

  • 首先使用HEAD请求建立连接
  • 为请求设置Expect:100-continue标头

选项1:首先使用HEAD请求建立连接我不像下一个选项那样喜欢这个连接,但它已成功运行。概念是HEAD请求根本没有数据并建立SSL连接而没有任何问题。然后你依靠你的HTTP库的底层实现来重用这个连接(大多数都这样做),没有进一步的SSL握手,你就避免了这个问题

选项2:为请求设置Expect:100-continue标头这是最佳选择。根据RFC,这就是为什么它确实存在!简单来说,一旦服务器准备好了请求(在这种情况下进行SSL协商之后),您将获得100状态,并可以继续POST或PUT您的数据。所有HTTP客户端库都实现了这一点(因为它是RFC的一部分),所以这很简单并且保证可以工作。下面是使用HttpWebRequest(或其中任何衍生产品)在.NET中设置此示例的示例。在代码中执行任何HTTP请求之前,在代码中执行此操作一次(例如在global.asax或Startup.cs中ServicePointManager.Expect100Continue = true;请参阅:ServicePointManager.Expect100Continue属性如果您使用较新的HttpClient类,则会自动添加此项(对于明显的原因)。

摘要强调文本尽管这已经存在了十多年的问题,但它从未找到任何面向公众的文档(很可能是因为Expect标题是我们老式类型的最佳实践,而较新的类和库都包含此标题默认)。

© www.soinside.com 2019 - 2024. All rights reserved.