Sam*_*ell 10 .net httpwebrequest servicepoint servicepointmanager
我正在努力解决这个错误:https:
//github.com/openstacknetsdk/openstack.net/issues/333
该问题涉及ProtocolViolationException以下消息:
HTTP/1.0协议不支持分块编码上载.
我发现我能够可靠地重现我发出生成502响应代码的Web请求的问题,然后调用使用带有分块编码的POST请求.我将其追溯到ServicePoint.HttpBehaviour具有HttpBehaviour.HTTP10502响应之后的值的属性.
我能够使用以下hack解决问题(在catch块中).此代码"隐藏" ServicePoint由失败请求创建的实例ServicePointManager,强制它ServicePoint为下一个请求创建新的实例.
public void TestProtocolViolation()
{
try
{
TestTempUrlWithSpecialCharactersInObjectName();
}
catch (WebException ex)
{
ServicePoint servicePoint = ServicePointManager.FindServicePoint(ex.Response.ResponseUri);
FieldInfo table = typeof(ServicePointManager).GetField("s_ServicePointTable", BindingFlags.Static | BindingFlags.NonPublic);
WeakReference weakReference = (WeakReference)((Hashtable)table.GetValue(null))[servicePoint.Address.GetLeftPart(UriPartial.Authority)];
if (weakReference != null)
weakReference.Target = null;
}
TestTempUrlExpired();
}
Run Code Online (Sandbox Code Playgroud)
问题:
答:.NET框架对HTTP服务器连接的支持基于ServicePointManager提供ServicePoint实例.每个ServicePoint实例都假定它基于端点地址连接到单个"逻辑"服务.此对象在另一端缓存有关服务的某些信息,其中一条信息是服务是否支持HTTP/1.1.如果对服务的任何请求指示该服务仅支持HTTP/1.0,则ServicePoint "锁存"到该状态,并且如果/当垃圾收集器清除指向该实例时,ServicePointManager将仅重新创建ServicePoint不处于该状态的新鲜状态WeakReference.
由于以下原因,此行为可能被视为不是问题:
通常,单个端点由单个服务提供服务,该服务支持或不支持HTTP/1.1.
如果端点实际上是一个负载均衡器,它将请求分派给多个后备HTTP实现(通常跨多个节点),那么这些节点代表同一整体服务安装的多个实例,并且所有节点都支持HTTP/1.1或者没有任何节点支持.
在上述情况不成立的极少数情况下,缺乏HTTP/1.0功能通常不会妨碍服务.部署一个或多个HTTP/1.0服务器的端点不太可能要求客户端使用HTTP/1.1功能发送请求.
答:肯定有解决办法,但一个或多个选项可能不适合特定环境.以下列出了其中一些选项.
更新服务以满足上面列出的条件.如果您提供的服务不符合上述条件,则应考虑在某些情况下.NET客户端可能无法与您的服务通信的情况下更新服务.如果您无法控制服务,显然这不是一个可行的解决方案.
考虑使用分块编码来上传文件的替代方案.如果您知道流的大小,则可能不需要使用分块编码,这样可以避免对HTTP/1.1的依赖.对于问题中提到的SDK的情况,底层的SimpleRESTServices库实际上需要事先知道流大小,因此分块编码实际上并未用于其预期目的.相反,当预先知道内容长度时,库应该使用缓冲传输,并且当Stream.Size属性抛出时,仅依赖于分块编码NotSupportedException.
考虑设置HttpWebRequest.AllowWriteStreamBuffering为true.虽然我没有测试过这个解决方案,但是在浏览参考源时收集的信息表明,在不支持分块传输的情况下,此属性允许实现回退到缓冲,而不是简单地抛出ProtocolViolationException.
强制将ServicePoint我的设置超时ServicePoint.MaxIdleTime为0.这仍然是hacky,但不依赖于反射,仍应继续使用Mono.修改后的代码如下所示.
public void TestProtocolViolation()
{
try
{
TestTempUrlWithSpecialCharactersInObjectName();
}
catch (WebException ex)
{
ServicePoint servicePoint = ServicePointManager.FindServicePoint(ex.Response.ResponseUri);
if (servicePoint.ProtocolVersion < HttpVersion.Version11)
{
int maxIdleTime = servicePoint.MaxIdleTime;
servicePoint.MaxIdleTime = 0;
Thread.Sleep(1);
servicePoint.MaxIdleTime = maxIdleTime;
}
}
TestTempUrlExpired();
}
Run Code Online (Sandbox Code Playgroud)| 归档时间: |
|
| 查看次数: |
3325 次 |
| 最近记录: |