答:.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(); }