System.ServiceModel
在运行时,默认向导生成的 SOAP Web 服务代理(如果 WCF 堆栈也是这种情况,则不是 100%)也可能出现同样的情况和错误:
- 最终用户机器被配置(在 Internet 设置中)使用不理解 HTTP 1.1 的代理
- 客户端最终发送了 HTTP 1.0 代理不理解的内容(通常是
Expect
作为 HTTPPOST
或PUT
请求的一部分的标头,因为标准协议约定分两部分发送请求,如此处的备注中所述)
... 产生 417。
如其他答案所述,如果您遇到的特定问题是Expect
标头导致问题,则可以通过相对全局关闭两部分 PUT/POST 传输来解决该特定问题System.Net.ServicePointManager.Expect100Continue
。
然而,这并不能解决完整的潜在问题——堆栈可能仍在使用 HTTP 1.1 特定的东西,例如 KeepAlives 等(尽管在许多情况下,其他答案确实涵盖了主要情况。)
然而,实际问题是自动生成的代码假定可以盲目地使用 HTTP 1.1 设施,因为每个人都理解这一点。要停止对特定 Web 服务代理的这种假设,可以通过创建一个派生的 Proxy 类来更改默认底层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 };
}
}