当我尝试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
并没有什么区别。
造成这种异常的原因是什么?
答案 0 :(得分:467)
System.Net.HttpWebRequest为每个请求添加标题'HTTP标头'Expect:100-Continue“',除非您明确要求它不要将this static property设置为false:
System.Net.ServicePointManager.Expect100Continue = false;
某些服务器会阻塞该标头并发回您看到的417错误。
试一试。
答案 1 :(得分:113)
另一种方式 -
将这些行添加到您的应用程序配置文件配置部分:
<system.net>
<settings>
<servicePointManager expect100Continue="false" />
</settings>
</system.net>
答案 2 :(得分:30)
在运行时,默认向导生成的SOAP Web服务代理(如果在WCF System.ServiceModel
堆栈中也是如此,则不是100%)也会出现同样的情况和错误:
Expect
标头作为HTTP POST
或PUT
请求的一部分请求分为两部分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)
: -
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 };
}
}
答案 3 :(得分:5)
您尝试模拟的表单是否有两个字段,用户名和密码?
如果是这样,这一行:
postData.Add("username", "password");
不正确。
你需要两行,如:
postData.Add("username", "Moose");
postData.Add("password", "NotMoosespasswordreally");
编辑:
好吧,既然这不是问题,解决这个问题的一种方法是使用像Fiddler或Wireshark这样的东西来成功观看从浏览器发送到Web服务器的内容,然后将其与您发送的内容进行比较码。如果您从.Net前往普通端口80,Fiddler仍将捕获此流量。
表单上可能还有一些其他隐藏字段,Web服务器期待您不发送。
答案 4 :(得分: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,通过在代理端的httpd.conf中设置此参数来解决问题{ {1}}无需在客户端进行任何更改,希望这会有所帮助。
答案 5 :(得分:2)
对于Powershell来说,它是
[System.Net.ServicePointManager]::Expect100Continue = $false
答案 6 :(得分:1)
如果您使用的是“ HttpClient ”,并且您不想使用全局配置来影响所有程序,则可以使用:
HttpClientHandler httpClientHandler = new HttpClientHandler();
httpClient.DefaultRequestHeaders.ExpectContinue = false;
我正在使用“ WebClient ”我认为您可以尝试通过调用来删除此标头:
var client = new WebClient();
client.Headers.Remove(HttpRequestHeader.Expect);
答案 7 :(得分:0)
在我的情况下,只有当我的客户端的计算机具有严格的防火墙策略时才会出现此错误,这会阻止我的程序与Web服务进行通信。
因此,我找到的唯一解决方案是捕获错误并通知用户手动更改防火墙设置。
答案 8 :(得分:0)
检查您的网络连接没有重定向。
在错误的wifi上,任何Web请求都重定向到公司登录页面时,我都遇到了这个问题。
答案 9 :(得分:-1)
web.config方法适用于对启用IntApp Web服务的规则的InfoPath表单服务调用。
<system.net>
<defaultProxy />
<settings> <!-- 20130323 bchauvin -->
<servicePointManager expect100Continue="false" />
</settings>
</system.net>