大型 WCF Web 服务请求因 (400) HTTP 错误请求而失败

Posted

技术标签:

【中文标题】大型 WCF Web 服务请求因 (400) HTTP 错误请求而失败【英文标题】:Large WCF web service request failing with (400) HTTP Bad Request 【发布时间】:2010-10-21 12:58:18 【问题描述】:

我遇到了这个明显常见的问题,但一直无法解决。

如果我调用我的 WCF Web 服务并在数组参数中使用相对较少的项目(我已经测试了多达 50 个),那么一切都很好。

但是,如果我使用 500 个项目调用 Web 服务,则会收到错误请求错误。

有趣的是,我在服务器上运行了Wireshark,看起来请求甚至没有到达服务器 - 客户端正在生成 400 错误。

例外情况是:

System.ServiceModel.ProtocolException:远程服务器返回意外响应:(400) 错误请求。 ---> System.Net.WebException:远程服务器返回错误:(400)错误请求。

我的客户端配置文件的 system.serviceModel 部分是:

 <system.serviceModel>
    <bindings>
        <wsHttpBinding>
            <binding name="WSHttpBinding_IMyService" closeTimeout="00:01:00"
                openTimeout="00:01:00" receiveTimeout="00:10:00" sendTimeout="00:01:00"
                bypassProxyOnLocal="false" transactionFlow="false" hostNameComparisonMode="StrongWildcard"
                maxBufferPoolSize="524288" maxReceivedMessageSize="2147483647"
                messageEncoding="Text" textEncoding="utf-8" useDefaultWebProxy="true"
                allowCookies="false">
                <readerQuotas maxDepth="32" maxStringContentLength="8192" maxArrayLength="2147483647"
                    maxBytesPerRead="4096" maxNameTableCharCount="16384" />
                <reliableSession ordered="true" inactivityTimeout="00:10:00"
                    enabled="false" />
                <security mode="None">
                    <transport clientCredentialType="Windows" proxyCredentialType="None"
                        realm="" />
                    <message clientCredentialType="Windows" negotiateServiceCredential="true"
                        establishSecurityContext="true" />
                </security>
            </binding>
        </wsHttpBinding>
    </bindings>
    <client>
        <endpoint address="http://serviceserver/MyService.svc"
            binding="wsHttpBinding" bindingConfiguration="WSHttpBinding_IMyService"
            contract="SmsSendingService.IMyService" name="WSHttpBinding_IMyService" />
    </client>
</system.serviceModel>

在服务器端,我的 web.config 文件有以下 system.serviceModel 部分:

<system.serviceModel>
    <services>
        <service name="MyService.MyService" behaviorConfiguration="MyService.MyServiceBehaviour" >
            <endpoint address="" binding="wsHttpBinding" bindingConfiguration="MyService.MyServiceBinding" contract="MyService.IMyService">
            </endpoint>
            <endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange"/>
        </service>
    </services>
    <bindings>
      <wsHttpBinding>
        <binding name="MyService.MyServiceBinding">
          <security mode="None"></security>
        </binding>
      </wsHttpBinding>
    </bindings>
    <behaviors>
        <serviceBehaviors>
            <behavior name="MyService.MyServiceBehaviour">
                <!-- To avoid disclosing metadata information, set the value below to false and remove the metadata endpoint above before deployment -->
                <serviceMetadata httpGetEnabled="true"/>
                <!-- To receive exception details in faults for debugging purposes, set the value below to true.  Set to false before deployment to avoid disclosing exception information -->
                <serviceDebug includeExceptionDetailInFaults="true"/>
            </behavior>
        </serviceBehaviors>
    </behaviors>
</system.serviceModel>

我有 looked at 和 fairly large number answers 到 this question 和 no success。

谁能帮我解决这个问题?

【问题讨论】:

如果没有到达服务器,可能是发送的数据有问题。也许请求中有一些非法字符?还假设这是 SOAP 所以您尝试将所有“最大”属性(例如 maxReceivedMessageSize...)设置为一个非常高的数字? 是的,它是 SOAP。并且请求应该没有任何问题 - 正如我所说,对于使用同一应用程序生成的多达 50 个元素,一切正常...... @mundeep - 是的 - 我尝试将它们全部设置为 2147483647,但没有运气。我链接到的一些页面实际上表明对所有属性都这样做是一件坏事...... 【参考方案1】:

尝试在服务器上设置 maxReceivedMessageSize,例如到 4MB:

<binding name="MyService.MyServiceBinding" maxReceivedMessageSize="4194304">

默认值(我相信是 65535)如此之低的主要原因是为了降低拒绝服务 (DoS) 攻击的风险。您需要将其设置为大于服务器上的最大请求大小和客户端上的最大响应大小。如果您在 Intranet 环境中,DoS 攻击的风险可能很低,因此使用远高于您预期需要的值可能是安全的。

顺便提几个解决连接到 WCF 服务问题的技巧:

如this MSDN article 中所述在服务器上启用跟踪。

在客户端使用 HTTP 调试工具(例如 Fiddler)检查 HTTP 流量。

【讨论】:

太棒了——就是这样。非常感谢您的回复! 感谢您提供启用跟踪的链接! 最后我也尝试过同样的做法,但尝不出成功的滋味。 有用的博文:geekswithblogs.net/smyers/archive/2011/10/05/… - 我只想向阅读此答案的人指出,答案中的上述代码 sn-p 应该进入绑定的绑定部分。例如:让绑定为 basicHttpBinding: - 也可能有设置(我必须)。【参考方案2】:

对于它的价值,使用 .NET 4.0 时的另一个注意事项是,如果在您的配置中找不到有效的端点,则会自动创建和使用默认端点。

默认端点将使用所有默认值,因此如果您认为您的服务配置具有较大的 maxReceivedMessageSize 等值,但配置有问题,您仍然会收到 400 Bad Request,因为默认端点将被创建和使用。

这是静默完成的,因此很难检测到。如果您在服务器上打开跟踪但没有其他指示(据我所知),您将看到有关此效果的消息(例如“未找到服务的端点,创建默认端点”或类似内容)。

【讨论】:

@user469104:非常好的提示。谢谢。有没有办法强制服务器使用手动声明的端点而不覆盖默认的 ServiceHost?【参考方案3】:

我也遇到了这个问题,但是上述方法都没有为我工作,因为我在长时间挖掘后使用自定义绑定(用于 BinaryXML)我在这里找到了答案:Sending large XML from Silverlight to WCF

由于使用 customBinding,maxReceivedMessageSize 必须在 web.config 中绑定元素下的 httpTransport 元素上设置:

<httpsTransport maxReceivedMessageSize="4194304" /> 

【讨论】:

【参考方案4】:

在 .NET 4.0 中的服务器 web.config 中,您还需要更改默认绑定。设置以下 3 个参数:

<basicHttpBinding>  
    <!-- http://www.intertech.com/Blog/post/NET-40-WCF-Default-Bindings.aspx  
         Enable transfer of large strings with maxBufferSize, maxReceivedMessageSize and maxStringContentLength
    -->  
       <binding **maxBufferSize="2147483647" maxReceivedMessageSize="2147483647"**>  
          <readerQuotas **maxStringContentLength="2147483647"**/>            
       </binding>
</basicHttpBinding>

【讨论】:

【参考方案5】:

调试客户端可能会很有用,关闭 Tools\Options\Debugging\General\'Enable Just My Code',点击 Debug\Exceptions\'catch all first-chance exceptions' 管理 CLR 异常,看看是否在协议异常之前和消息到达网络之前,客户端上有一个异常。 (我的猜测是某种序列化失败。)

【讨论】:

【参考方案6】:

您还可以打开 WCF 日志记录以获取有关原始错误的更多信息。这帮助我解决了这个问题。

将以下内容添加到您的 web.config,它将日志保存到 C:\log\Traces.svclog

<system.diagnostics>
    <sources>
        <source name="System.ServiceModel"
                  switchValue="Information, ActivityTracing"
                  propagateActivity="true">
            <listeners>
                <add name="traceListener"
                     type="System.Diagnostics.XmlWriterTraceListener"
                     initializeData= "c:\log\Traces.svclog" />
            </listeners>
        </source>
    </sources>
</system.diagnostics>

【讨论】:

有时最简单的答案是最好的。对我来说,我发现我在流响应调用中返回了一个空 Stream 对象。 svclog 在几秒钟内解决了这个问题。谢谢。【参考方案7】:

只想指出

除了 MaxRecivedMessageSize 之外,ReaderQuotas 下还有一些属性,你可能会达到项目数量限制而不是大小限制。 MSDN 链接是here

【讨论】:

【参考方案8】:

我找到了错误请求 400 问题的答案。

这是默认的服务器绑定设置。您需要添加到服务器和客户端默认设置。

<binding name="" openTimeout="00:10:00" closeTimeout="00:10:00" receiveTimeout="00:10:00" sendTimeout="00:10:00" maxReceivedMessageSize="2147483647" maxBufferPoolSize="2147483647" maxBufferSize="2147483647">
    <security mode="None"/>
    <readerQuotas maxStringContentLength="2147483647"/>
</binding>

【讨论】:

【参考方案9】:

在我的情况下,即使在尝试了所有解决方案并将所有限制设置为最大值之后,它也无法正常工作。最后我发现在 IIS/网站上安装了一个 Microsoft IIS 过滤模块Url Scan 3.1,它有自己的限制,可以根据内容大小拒绝传入的请求并返回“404 Not found page”。

通过将MaxAllowedContentLength 设置为所需的值,可以在%windir%\System32\inetsrv\urlscan\UrlScan.ini 文件中更新它的限制。

例如。以下将允许最多 300 mb 的请求

MaxAllowedContentLength=314572800

希望对某人有所帮助!

【讨论】:

以上是关于大型 WCF Web 服务请求因 (400) HTTP 错误请求而失败的主要内容,如果未能解决你的问题,请参考以下文章

WCF REST 服务 400 错误请求

WCF 服务 400 错误请求

wcf 服务错误请求 400 流式传输

WCF:自托管服务上的 HTTP 400 错误请求

尝试使用 XHR 联系 WCF 服务时出现 400 错误请求

IIS 托管的 WCF 服务返回 HTTP 400 错误请求