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

当我尝试POST到一个URL会导致以下exception:

远程服务器返回错误:(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没有任何区别。

什么导致这个exception?

System.Net.HttpWebRequest为每个请求添加头“HTTP头”期望:100-继续“',除非你明确地要求不要通过设置这个静态属性为false:

 System.Net.ServicePointManager.Expect100Continue = false; 

某些服务器在该标题上窒息并发回您看到的417错误。

给一个镜头。

其他方式 –

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

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

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

  • 最终用户机器被configuration(在Internet设置中)使用不理解HTTP 1.1的代理
  • 客户端最终会发送一个HTTP 1.0代理不理解的东西(通常是一个Expect头文件作为HTTP POST或者PUT请求的一部分,这是由于标准的协议规定了两个部分的发送请求,

产生一个417

正如其他答案中所述,如果遇到的特定问题是Expect标题导致问题,那么可以通过相对全局地closures通过System.Net.ServicePointManager.Expect100Continue的两部分PUT / POST传输来路由该特定问题System.Net.ServicePointManager.Expect100Continue

然而,这并不能解决完整的底层问题 – 堆栈可能仍然使用HTTP 1.1特定的东西,例如KeepAlive等(虽然在很多情况下其他答案都覆盖了主要的情况)。

然而,实际的问题是,自动生成的代码假定可以盲目地使用HTTP 1.1设施,因为每个人都明白这一点。 要停止对特定Web Service代理的这种假设,可以通过创build一个覆盖protected override WebRequest GetWebRequest(Uri uri)的派生代理类来更改默认的基础HttpWebRequest.ProtocolVersion的默认值1.1 , 如下所示 :

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

MyWS是“添加Web引用”向MyWS您吐出的代理。)


更新:这是我在生产中使用的一个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 }; } } 

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

如果是这样,这一行:

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

是不正确的。

你需要两行:

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

编辑:

好的,因为这不是问题,所以解决这个问题的一个方法就是使用Fiddler或Wireshark这样的东西来成功地从浏览器中查看正在发送到Web服务器的内容,然后将其与您的代码发送的内容进行比较。 如果你要从.Net的正常端口80,提琴手仍然会捕获这个stream量。

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

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

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

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

我正在使用“ WebClient ”我想你可以尝试删除这个标题通过调用:

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

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

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

在我的情况下,这个错误似乎只有当我的客户端的计算机有一个严格的防火墙策略,这阻止了我的程序与Web服务通信。

所以我唯一能find的解决scheme是捕获错误并通知用户手动更改防火墙设置。