GetResponse() 和 WebException 杀死我的线程

Posted

技术标签:

【中文标题】GetResponse() 和 WebException 杀死我的线程【英文标题】:GetResponse() and WebException kill my thread 【发布时间】:2017-07-16 13:32:49 【问题描述】:

我实际上遇到了一个停止我的线程的 httpWebResponse 问题。

我每 2 秒在循环线程中调用一个 ApiCall 方法。这在大多数情况下都有效。但有时request.GetResponse() 会抛出 WebException 并停止我的主线程循环。它会冻结应用程序而不会使其崩溃。它可以重试 5 次(MaxRetries)而不能正常工作。我不明白发生了什么。

这是 ApiCall 方法的代码部分。我真的不知道它对谁起作用。所以在这里和那里拿起了一些代码。我一定错过了什么……但是什么?

public T CallWithJsonResponse<T>(string uri, bool hasEffects, params Tuple<string, string>[] headers)
    
        if (simulate && hasEffects)
        
            Debug.WriteLine("(simulated)" + GetCallDetails(uri));
            return default(T);
        

        Debug.WriteLine(GetCallDetails(uri));
        var request = HttpWebRequest.CreateHttp(uri);
        foreach (var header in headers)
        
            request.Headers.Add(header.Item1, header.Item2);
        
        HttpWebResponse response = null;
        request.Timeout = 300000;

        for (int i = 0; i < MaxRetries; i++)
        

            try
            
                response = null;
                using (response = (HttpWebResponse)request.GetResponse())
                
                    if (response.StatusCode == HttpStatusCode.OK)
                    
                        try
                        
                            using (var sr = new StreamReader(response.GetResponseStream()))
                            
                                var content = sr.ReadToEnd();
                                var jsonResponse = JsonConvert.DeserializeObject<ApiCallResponse<T>>(content);
                                sr.Close();
                                response.Close();

                                if (jsonResponse.success)
                                
                                    //GC.Collect();
                                    GC.WaitForPendingFinalizers();
                                    return jsonResponse.result;
                                
                                else
                                

                                    Console.WriteLine(new Exception(jsonResponse.message.ToString()));

                                
                            
                        
                        catch (Exception ex)
                        

                            Console.WriteLine("Error - Call Details=" + GetCallDetails(uri) + "Exeption: " + ex.ToString());

                        
                    
                    else
                    
                        Console.WriteLine("Error - StatusCode=" + response.StatusCode + " Call Details=" + GetCallDetails(uri));

                    
                
            
            catch (WebException wex)
            
                if (wex.Response != null)
                
                    Console.WriteLine("ERROR (web exception, response generated): " + Environment.NewLine + new StreamReader(wex.Response.GetResponseStream()).ReadToEnd());
                
                else
                
                    Console.WriteLine("ERROR (web exception, NO RESPONSE): " + wex.Message + wex.StackTrace);
                
                Console.WriteLine("Error - Call Details=" + GetCallDetails(uri));

            
            catch (Exception ex)
            
                Console.WriteLine("Error - Call Details=" + GetCallDetails(uri) + "Exception: " + ex.ToString());
            
        
        return default(T);
    

private static string GetCallDetails(string uri)
    
        StringBuilder sb = new StringBuilder();
        var u = new Uri(uri);
        sb.Append(u.AbsolutePath);
        if (u.Query.StartsWith("?"))
        
            var queryParameters = u.Query.Substring(1).Split('&');
            foreach (var p in queryParameters)
            
                if (!(p.ToLower().StartsWith("api") || p.ToLower().StartsWith("nonce")))
                
                    var kv = p.Split('=');
                    if (kv.Length == 2)
                    
                        if (sb.Length != 0)
                        
                            sb.Append(", ");
                        

                        sb.Append(kv[0]).Append(" = ").Append(kv[1]);
                    
                
            
        
        return sb.ToString();
    

【问题讨论】:

我不清楚你遇到了什么问题,你的问题是什么。 请更新您的帖子以包含GetCallDetails 方法的源代码。 好吧,我想让代码在 WebException 发生后继续运行。但是 WebException 似乎停止了当前线程并冻结了我的应用程序。其他例外只是在控制台中写入一些文本并且应用程序继续运行。 ApiCall 不是强制性的。如果失败了,也没关系。下一次尝试将在下一个循环中完成。但是有了 WebException,下一个循环就永远不会出现了…… 如果您发出网络请求并得到响应,我发现您应该始终使用响应(如果有响应)。这意味着读取响应流以完成。在不成功代码的情况下,有时会在 WebException 上找到响应。不这样做可能会导致负载挂起。 你的意思是我需要读取WebException里面的响应? 【参考方案1】:

我建议改变:

catch (WebException wex)

    if (wex.Response != null)
    
        Console.WriteLine("ERROR (web exception, response generated): " + Environment.NewLine + new StreamReader(wex.Response.GetResponseStream()).ReadToEnd());
    
    else
    
        Console.WriteLine("ERROR (web exception, NO RESPONSE): " + wex.Message + wex.StackTrace);
    
    Console.WriteLine("Error - Call Details=" + GetCallDetails(uri));


到:

catch (WebException wex)

    try
    
        if (wex.Response != null)
        
            Console.WriteLine("ERROR (web exception, response generated): " + Environment.NewLine +
                              new StreamReader(wex.Response.GetResponseStream()).ReadToEnd());
        
        else
        
            Console.WriteLine("ERROR (web exception, NO RESPONSE): " + wex.Message + wex.StackTrace);
        
        Console.WriteLine("Error - Call Details=" + GetCallDetails(uri));
    
    catch (Exception bob)
    
        // Ignore exceptions here
    

然后在 catch (Exception bob) 行设置断点 - 看看为什么你现有的 catch 块失败。

【讨论】:

非常感谢,我试试看。【参考方案2】:

嗯,它似乎工作正常,我试着像你说的 Spender 一样消耗每一个响应。 正如你所说的 mjwills,我还将 try catch 放在 WebException catch 中,但它永远不会捕获。所以我认为消耗每个响应是解决我问题的方法。谢谢 !现在我需要在一周内监控应用程序,看看它是否健壮。

【讨论】:

【参考方案3】:

不...它没有改变任何东西。我创建了一些方法来检查发生 WebException 后线程是否仍然存在。你猜怎么着! try/catch 工作正常,我收到 WebException。但就在片刻之后,线程停止或崩溃。不知道女巫是正确的......所以如果线程被杀死,我实现了自动重启......这很丑陋,但它有效。

这个 request.GetResponse() 是怎么回事?为什么即使捕获到异常它也会杀死线程?很奇怪……

【讨论】:

以上是关于GetResponse() 和 WebException 杀死我的线程的主要内容,如果未能解决你的问题,请参考以下文章

HttpWebRequest的GetResponse或GetRequestStream偶尔超时 + 总结各种超时死掉的可能和相应的解决办法

HttpWebRequest.GetResponse 方法卡住特定的 url

C# HttpWebRequest.GetResponse - 如何处理非异常与 webexception 响应的 StatusCode 使用情况?

GetResponse() 仅在我的计算机上慢

转载HttpWebRequest的GetResponse或GetRequestStream偶尔超时 + 总结各种超时死掉的可能和相应的解决办法

HttpWebRequest.GetResponse() 不断超时