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

Sae*_*ini 209 .net c# webclient http http-post

当我尝试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.
Run Code Online (Sandbox Code Playgroud)

使用一HttpWebRequest/HttpWebResponse对或一HttpClient对没有区别.

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

xcu*_*cud 471

System.Net.HttpWebRequest为每个请求添加标题'HTTP标头'Expect:100-Continue"',除非您明确要求它不要将此静态属性设置为false:

System.Net.ServicePointManager.Expect100Continue = false;
Run Code Online (Sandbox Code Playgroud)

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

试一试.

  • 您还可以在app.config中指定该属性:<system.net> <settings> <servicePointManager expect100Continue ="false"/>.http://nahidulkibria.blogspot.com/2009/06/how-to-fix-wcf-error-remote-server.html (25认同)
  • 我想我在Jon Skeet发布解决方案的帖子中获得了额外的10分,以获得答案. (8认同)
  • 我有一些与Twitter交谈的代码在圣诞节后的第二天突然停止工作.他们完成了升级或配置更改,导致他们的服务器开始阻塞该标头.找到修复是一件痛苦的事. (5认同)
  • 注意:此设置也适用于ServiceReferences,我假设WebReferences. (2认同)

Eng*_*dıç 114

其他方式 -

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

<system.net>
    <settings>
        <servicePointManager expect100Continue="false" />
    </settings>
</system.net>
Run Code Online (Sandbox Code Playgroud)

  • 当您必须进行操作更改并且尚未准备好更改代码时,可以很好地工作. (6认同)
  • 那一行配置有什么作用? (2认同)

Rub*_*ink 31

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

  • 最终用户计算机已配置(在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;
    }
}
Run Code Online (Sandbox Code Playgroud)

(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 };
    }
}
Run Code Online (Sandbox Code Playgroud)

  • 我知道你不久前发布了这个,但鲁本,你是一个救生员.这个问题让我疯狂,直到我遇到你的解决方案并且它完美无缺.干杯! (2认同)

Moo*_*ose 5

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

如果是这样,这一行:

 postData.Add("username", "password");
Run Code Online (Sandbox Code Playgroud)

是不正确的.

你需要两行,如:

 postData.Add("username", "Moose");
postData.Add("password", "NotMoosespasswordreally");
Run Code Online (Sandbox Code Playgroud)

编辑:

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

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