【问题标题】:How to request an aborted HttpWebRequest again?如何再次请求中止的 HttpWebRequest?
【发布时间】:2009-01-05 00:22:12
【问题描述】:

我的目标是在异步 HttpWebRequest 失败时重试它。

当我 Abort() 一个 HttpWebRequest 时,我不能再次 BeginGetResponse()。所以再次请求的唯一方法可能是重新创建 HttpWebRequest 对象。这似乎需要做很多工作,因为我必须从旧对象中复制所有属性。有什么捷径吗?

注意:我认为序列化可以解决我的问题,但是这个类不会序列化,正如previous question 中所讨论的那样。

更新删除示例源代码,因为它是不必要的

目前对此事的看法没有捷径,重做请求的唯一方法是创建另一个 HttpWebRequest 对象,方法与创建原始对象相同。

【问题讨论】:

    标签: c# .net httpwebrequest


    【解决方案1】:

    这是不可能的。

    一个 HTTPWebRequest 实例实际上代表一个请求实例(尽管在某些极端情况下它会在内部重试),因此在逻辑上不是可以重复的东西。它能够只返回一个响应(请求/响应是逻辑对),尽管您可以多次检查该响应,但您将获得完全相同的对象。

    基本上,您认为 HTTPWebRequest 实例是一种工厂,但它确实是具体的。您必须创建另一个实例。

    【讨论】:

    • 有办法,看看我的回答。
    【解决方案2】:

    有可能!

    您只需要创建一个新的HttpWebRequest 并通过反射将旧对象的所有属性复制到它。

    这是一个扩展方法,它可以做到这一点:

    /// <summary>
    /// Clones a HttpWebRequest for retrying a failed HTTP request.
    /// </summary>
    /// <param name="original"></param>
    /// <returns></returns>
    public static HttpWebRequest Clone(this HttpWebRequest original)
    {
        // Create a new web request object
        HttpWebRequest clone = (HttpWebRequest)WebRequest.Create(original.RequestUri.AbsoluteUri);
    
        // Get original fields
        PropertyInfo[] properties = original.GetType().GetProperties(BindingFlags.Public | BindingFlags.Instance);
    
        // There are some properties that we can't set manually for the new object, for various reasons
        List<string> excludedProperties = new List<String>(){ "ContentLength", "Headers" };
    
        // Traverse properties in HttpWebRequest class
        foreach (PropertyInfo property in properties)
        {
            // Make sure it's not an excluded property
            if (!excludedProperties.Contains(property.Name))
            {
                // Get original field value
                object value = property.GetValue(original);
    
                // Copy the value to the new cloned object
                if (property.CanWrite)
                {
                    property.SetValue(clone, value);
                }
            }
        }
    
        return clone;
    }
    

    当您想重新发出相同的请求时,只需执行以下操作:

    // Create a request
    HttpWebRequest request = (HttpWebRequest)HttpWebRequest.Create("https://www.google.com/");
    
    // Change some properties...
    
    // Execute it
    HttpWebResponse response = (HttpWebResponse)request.GetResponse();
    
    // Clone the request to reissue it using our extension method
    request = request.Clone();
    
    // Execute it again
    response = (HttpWebResponse)request.GetResponse();
    

    【讨论】:

    • 太棒了。谢谢。
    • 好主意!但是,我不确定您不想要复制哪些标头。例如,如果您有授权信息,则需要复制标头(至少其中一些)以便下次尝试成功。
    • 扩展方法不会复制标头,因为 C# 在尝试将整个标头写入该属性时会引发异常。您需要调整代码以将每个单独的标头作为键、值对读取并将其写入新的克隆对象,一次一个标头。
    【解决方案3】:

    您在哪里尝试序列化请求?最好在您尝试发出请求之前序列化请求,然后在失败时重新发送请求(从序列化实例)。

    此外,您可能希望删除代理、序列化实例,然后重新设置代理,因为这似乎是序列化请求的问题所在。

    【讨论】:

    • 完整的代码不包含序列化,因为它不起作用,但如果我在代码中包含序列化,我肯定会按照你说的做。我为序列化测试编写的那段代码没有任何关于代理的行,我不知道如何删除它。你呢?
    • 删除了序列化示例代码并将其替换为另一个关于序列化 HttpWebRequest (stackoverflow.com/questions/351265/…) 的 SO Question 的链接
    【解决方案4】:

    没有捷径,重做请求的唯一方法是创建另一个 HttpWebRequest 对象,就像创建原始对象一样。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2011-01-28
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-02-14
      • 2016-04-01
      • 1970-01-01
      相关资源
      最近更新 更多