gpt4 book ai didi

.net - 在 WebException 之后避免 ProtocolViolationException

转载 作者:行者123 更新时间:2023-12-01 07:44:55 25 4
gpt4 key购买 nike

我正在努力解决这个错误:
https://github.com/openstacknetsdk/openstack.net/issues/333

问题涉及 ProtocolViolationException带有以下消息:

Chunked encoding upload is not supported on the HTTP/1.0 protocol.



我发现我能够可靠地重现问题,我发出一个产生 502 响应代码的 Web 请求,然后调用使用带有分 block 编码的 POST 请求。我将其追溯到 ServicePoint.HttpBehaviour 值为 HttpBehaviour.HTTP10 的属性在 502 响应之后。

我能够使用以下 hack(在 catch block 中)解决问题。此代码“隐藏” 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();
}

问题:
  • 为什么我要观察这种行为?
  • 解决问题的非hacky方法是什么?
  • 最佳答案

    问:为什么我会观察到这种行为?

    A. .NET 框架对连接到 HTTP 服务器的支持基于 ServicePointManager提供ServicePoint实例。每个ServicePoint实例假设它基于端点地址连接到单个“逻辑”服务。此对象缓存有关另一端服务的某些信息,其中一条信息是该服务是否支持 HTTP/1.1。如果对服务的任何请求表明该服务仅支持 HTTP/1.0,ServicePoint "latches" into that state ,以及 ServicePointManager只会重新创建一个新的 ServicePoint如果/当垃圾收集器清除 WeakReference 时,则不会处于该状态指向实例。

    由于以下原因,此行为可能被认为不是问题:

  • 通常,单个端点由单个服务提供服务,并且该服务支持或不支持 HTTP/1.1。
  • 如果一个端点实际上是一个负载均衡器,它将请求分派(dispatch)到多个支持 HTTP 实现(通常跨多个节点),那么这些节点代表同一整体服务安装的多个实例,并且要么所有节点都支持 HTTP/1.1,要么没有节点支持。
  • 在上述不成立的极少数情况下,缺乏 HTTP/1.0 特性通常不会成为服务的障碍。部署一个或多个 HTTP/1.0 服务器的端点不太可能要求客户端使用 HTTP/1.1 功能发送请求。

  • 问:有没有解决问题的简单方法?

    A. 当然有变通办法,但其中一个或多个选项可能不适合特定环境。下面列出了其中一些选项。
  • 更新服务以满足上述条件。 如果您提供的服务不符合上述条件,您应该考虑更新服务,前提是 .NET 客户端在某些情况下可能无法与您的服务通信。如果您无法控制服务,显然这不是一个可行的解决方案。
  • 考虑使用分 block 编码上传文件的替代方法。 如果您知道流的大小,则可能不需要使用分 block 编码,这样可以避免对 HTTP/1.1 的依赖。对于问题中提到的 SDK 的情况,底层的 SimpleRESTServices 库实际上需要提前知道流大小,因此分 block 编码实际上并未用于其预期目的。相反,当预先知道内容长度时,库应该使用缓冲传输,并且仅在 Stream.Size 时才依赖分 block 编码。属性抛出 NotSupportedException .
  • 考虑设置 HttpWebRequest.AllowWriteStreamBuffering true . 虽然我没有测试过这个解决方案,但是在浏览引用源时收集的信息表明这个属性允许实现 fall back to buffering在不支持分 block 传输的情况下,而不是简单地 throwing the 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();
    }
  • 关于.net - 在 WebException 之后避免 ProtocolViolationException,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/22973178/

    25 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com