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

问题描述 投票:208回答:9

当我尝试POST到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并没有什么区别。

造成这种异常的原因是什么?

c# .net http http-post webclient
9个回答
467
投票

System.Net.HttpWebRequest为每个请求添加标题'HTTP标头'Expect:100-Continue“',除非您明确要求它不要将this static property设置为false:

System.Net.ServicePointManager.Expect100Continue = false;

有些服务器会阻塞该标头并发回您看到的417错误。

试一试。


113
投票

其他方式 -

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

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

30
投票

在运行时,默认向导生成的SOAP Web服务代理(如果在WCF System.ServiceModel堆栈中也是如此),也会出现同样的情况和错误:

  • 最终用户计算机已配置(在Internet设置中)以使用不了解HTTP 1.1的代理
  • 客户端最终发送HTTP 1.0代理不理解的东西(通常是Expect头作为HTTP POSTPUT请求的一部分,因为标准协议约定以两部分as covered in the Remarks here发送请求)

...产生417。

正如其他答案中所述,如果您遇到的具体问题是Expect标头导致问题,那么可以通过System.Net.ServicePointManager.Expect100Continue对两部分PUT / POST传输进行相对全局关闭来绕过该特定问题。 。

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

然而,实际问题是自动生成的代码假定可以盲目地使用HTTP 1.1工具,因为每个人都理解这一点。要停止对特定Web服务代理的这种假设,可以通过创建一个覆盖HttpWebRequest.ProtocolVersion 1.1的派生代理类来更改默认的protected override WebRequest GetWebRequest(Uri uri)默认底层as shown in this post: -

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

(其中MyWS是添加Web引用向导吐出的代理。)


更新:这是我在生产中使用的一个impl:

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 };
    }
}

5
投票

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

如果是这样,这一行:

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

是不正确的。

你需要两行,如:

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

编辑:

好的,因为这不是问题,解决这个问题的一种方法是使用像Fiddler或Wireshark这样的东西来成功地观察从浏览器发送到Web服务器的内容,然后将其与您的代码发送的内容进行比较。如果您要从.Net前往普通端口80,Fiddler仍将捕获此流量。

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


3
投票

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


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>
© www.soinside.com 2019 - 2024. All rights reserved.