首页 文章

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

提问于
浏览
205

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

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

9 回答

  • 30

    System.Net.HttpWebRequest将标头'HTTP header 806241 '添加到每个请求,除非您明确要求它不要将this static property设置为false:

    System.Net.ServicePointManager.Expect100Continue = false;
    

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

    试一试 .

  • 0

    其他方式 -

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

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

    在运行时,默认向导生成的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传输来绕过该特定问题 . .

    However this does not fix the complete underlying problem - the stack may still be using HTTP 1.1 specific things such as KeepAlives etc. (though in many cases the other answers do cover the main cases.)

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

    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服务器期望您不发送该字段 .

  • -1

    从代理端解决方案,我在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中设置此参数而不需要在客户端更改任何内容来解决问题,希望这可以帮助 .

  • 1

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

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

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

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

    对于Powershell来说

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

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

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

  • 460

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

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

相关问题