HTTP POST返回错误:417“预期失败。”


212

当我尝试发布到URL时,会导致以下异常:

远程服务器返回错误:(417)预期失败。

这是一个示例代码:

var client = new WebClient();

var postData = new NameValueCollection();
postData.Add("postParamName", "postParamValue");

byte[] responseBytes = client.UploadValues("http://...", postData);
string response = Encoding.UTF8.GetString(responseBytes); // (417) Expectation Failed.

使用一HttpWebRequest/HttpWebResponse对或一个HttpClient并没有什么不同。

是什么导致此异常?


2
当您的应用程序通过代理服务器进行通信时,似乎会发生此问题。我编写的.NET应用程序在直接连接到Internet时有效,但在代理服务器后面却不起作用。
Salman A

2
当客户端通过HTTP 1.0(仅)代理服务器运行时,观察到这种情况。客户端(没有任何配置的asmx代理)正在发送HTTP 1.1请求,然后代理(在没有任何服务器参与之前)便拒绝代理继续发送的内容。如果最终用户有这个问题,采用以下配置的解决方案是一个合适的解决方法,因为它会导致没有对代理理解的依赖要产生的请求Expect在默认情况下被添加作为标题Expect100Continuetrue默认。
Ruben Bartelink 2012年

Answers:


478

System.Net.HttpWebRequest会将标头“ HTTP标头“ Expect:100-Continue”“添加到每个请求,除非您通过将此静态属性设置为false 明确要求不要这样做:

System.Net.ServicePointManager.Expect100Continue = false;

一些服务器在该标头上阻塞,然后将您看到的417错误发送回去。

试一试。


5
我有一些与Twitter交流的代码,在圣诞节后的第二天突然停止工作。他们进行了升级或配置更改,导致服务器开始在该标头上阻塞。找到解决办法很痛苦。
xcud

8
我想我在Jon Skeet发布解决方案的线程中获得了一个额外的10分。
xcud

1
谢谢!这应该在msdn示例(例如msdn.microsoft.com/en-us/library/debx8sh9.aspx)中的
Eugene,

25
您也可以在app.config中指定该属性:<system.net> <settings> <servicePointManager Expect100Continue =“ false” />。nahidulkibria.blogspot.com/2009/06/...
安德烈Luus

2
注意:此设置也适用于ServiceReferences,并且我假设使用WebReferences。
Myster

114

其他方式 -

将这些行添加到您的应用程序配置文件配置部分:

<system.net>
    <settings>
        <servicePointManager expect100Continue="false" />
    </settings>
</system.net>

6
当您必须进行操作性更改并且还没有准备好进行代码更改时,它可以很好地工作。
dawebber 2013年

1
那行配置做什么?
J86

31

System.ServiceModel在运行时,默认的向导生成的SOAP Web服务代理(如果在WCF 堆栈中也是如此,则不是100%)也会产生这种相同的情况和错误:

  • 最终用户计算机(在“ Internet设置”中)配置为使用不理解HTTP 1.1的代理
  • 客户端最终会发送HTTP 1.0代理无法理解的内容(通常,Expect标头作为HTTP POSTPUT请求的一部分,这是由于将请求分为两部分发送的标准协议,如此处的“备注”所述

...产生417。

如其他答案所述,如果您遇到的特定问题是Expect标题引起了问题,则可以通过相对全局地关闭两部分式PUT / POST传输(通过)来解决该特定问题System.Net.ServicePointManager.Expect100Continue

但这不能解决完整的潜在问题-堆栈可能仍在使用HTTP 1.1特定的东西,例如KeepAlives等。(尽管在许多情况下,其他答案确实涵盖了主要情况)。

但是实际的问题是,自动生成的代码假定可以使用HTTP 1.1设施盲目地进行,因为每个人都理解这一点。为了制止这种假设为特定的Web服务代理,可以改变覆盖默认的基本HttpWebRequest.ProtocolVersion从默认的1.1通过创建覆盖派生Proxy类如图这篇文章: -protected override WebRequest GetWebRequest(Uri uri)

public class MyNotAssumingHttp11ProxiesAndServersProxy : MyWS
{
    protected override WebRequest GetWebRequest(Uri uri)
    {
      HttpWebRequest request = (HttpWebRequest)base.GetWebRequest(uri);
      request.ProtocolVersion = HttpVersion.Version10;
      return request;
    }
}

MyWS“添加Web参考”向导出现在您的代理那里。)


更新:这是我在生产中使用的暗示:

class ProxyFriendlyXXXWs : BasicHttpBinding_IXXX
{
    public ProxyFriendlyXXXWs( Uri destination )
    {
        Url = destination.ToString();
        this.IfProxiedUrlAddProxyOverriddenWithDefaultCredentials();
    }

    // Make it squirm through proxies that don't understand (or are misconfigured) to only understand HTTP 1.0 without yielding HTTP 417s
    protected override WebRequest GetWebRequest( Uri uri )
    {
        var request = (HttpWebRequest)base.GetWebRequest( uri );
        request.ProtocolVersion = HttpVersion.Version10;
        return request;
    }
}

static class SoapHttpClientProtocolRealWorldProxyTraversalExtensions
{
    // OOTB, .NET 1-4 do not submit credentials to proxies.
    // This avoids having to document how to 'just override a setting on your default proxy in your app.config' (or machine.config!)
    public static void IfProxiedUrlAddProxyOverriddenWithDefaultCredentials( this SoapHttpClientProtocol that )
    {
        Uri destination = new Uri( that.Url );
        Uri proxiedAddress = WebRequest.DefaultWebProxy.GetProxy( destination );
        if ( !destination.Equals( proxiedAddress ) )
            that.Proxy = new WebProxy( proxiedAddress ) { UseDefaultCredentials = true };
    }
}

2
我知道您很早以前就发布了这篇文章,但是鲁本,您可以挽救生命。在我遇到您的解决方案之前,这个问题一直使我发疯,并且效果很好。干杯!
Christopher McAtackney 2012年

1
@ChrisMcAtackney不客气。在他们的时间记录它似乎确实值得努力...一般问题围绕着成为最高优先级问题的边缘而定,直到我进行了适当的调查之前一直困扰着我-但是似乎没有任何Google果汁可以问题的那一边。这是阿特伍德(Attwood)小伙子从很早以前就发布的帖子之一,这促使我去做。(带有这样评论的
赞誉

1
精彩的附加内容和示例。谢谢!
Fadi Chamieh 2014年

5

您尝试模仿的表单是否有两个字段,用户名和密码?

如果是这样,则此行:

 postData.Add("username", "password");

是不正确的。

您将需要两行内容,例如:

 postData.Add("username", "Moose");
postData.Add("password", "NotMoosespasswordreally");

编辑:

好的,因为这不是问题,解决此问题的一种方法是使用Fiddler或Wireshark之​​类的工具成功查看从浏览器发送到Web服务器的内容,然后将其与从代码发送的内容进行比较。如果您要从.Net转到普通端口80,Fiddler仍将捕获此流量。

Web服务器期望您未发送的表单上可能还有其他一些隐藏字段。


3

从代理端的解决方案,我在SSL握手过程中遇到了一些问题,在SetEnv force-proxy-request-1.0 1 SetEnv proxy-nokeepalive 1面对417错误之后,我不得不通过在httpd.conf中设置此参数来强制代理服务器使用HTTP / 1.0发送请求以解决该问题。我的客户应用程序使用HTTP / 1.1,并且代理被迫使用HTTP / 1.0,此问题已通过在代理端的httpd.conf中设置此参数RequestHeader unset Expect early而无需在客户端进行任何更改来解决,希望这会有所帮助。


2

对于Powershell,它是

[System.Net.ServicePointManager]::Expect100Continue = $false

1

如果您使用的是“ HttpClient ”,并且您不想使用全局配置来影响您的所有程序,则可以使用:

 HttpClientHandler httpClientHandler = new HttpClientHandler();
 httpClient.DefaultRequestHeaders.ExpectContinue = false;

我使用的是“ WebClient ”,我认为您可以尝试通过调用以下方法删除此标头:

 var client = new WebClient();
 client.Headers.Remove(HttpRequestHeader.Expect);

0

在我的情况下,仅当我的客户端计算机具有严格的防火墙策略时,才会出现此错误,这会阻止我的程序与Web服务进行通信。

因此,我能找到的唯一解决方案是捕获错误并通知用户有关手动更改防火墙设置的信息。


-1

web.config方法适用于对IntApp Web服务启用的规则的InfoPath表单服务调用。

  <system.net>
    <defaultProxy />
    <settings> <!-- 20130323 bchauvin -->
        <servicePointManager expect100Continue="false" />
    </settings>
  </system.net>

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.