Skip to main content
 首页 » 编程设计

c#之为什么我会遇到超时异常以及在使用 httpwebrequest 下载文件时我应该如何处理

2024年01月24日28shihaiming

这是代码:

HttpWebRequest request; 
        int currentIndex = 0; 
        void fileDownloadRadar(string uri, string fileName) 
        { 
            if (splash != null) 
            { 
                if (!splash.IsDisposed) 
                    splash.UpdateProgressBar(0); 
            } 
            /*_request = WebRequest.Create(uri) as HttpWebRequest; 
            _request.CookieContainer = new CookieContainer(); 
            _request.AllowAutoRedirect = true; 
            _responseAsyncResult = _request.BeginGetResponse(ResponseCallback, null);*/ 
            request = (System.Net.HttpWebRequest)System.Net.WebRequest.Create(uri); 
            request.CookieContainer = new CookieContainer(); 
            request.AllowAutoRedirect = true; 
 
            HttpWebResponse response = (HttpWebResponse)request.GetResponse(); 
            long contentLength = response.ContentLength; 
            if (response.ContentType == "") 
            { 
                Logger.Write("ContentType is Empty download was not fine !!!!!"); 
            } 
            if ((response.StatusCode == HttpStatusCode.OK || 
                response.StatusCode == HttpStatusCode.Moved || 
                response.StatusCode == HttpStatusCode.Redirect) && 
                response.ContentType.StartsWith("image", StringComparison.OrdinalIgnoreCase)) 
            { 
                Logger.Write("ContentType is not empty meaning download is fine"); 
                using (Stream inputStream = response.GetResponseStream()) 
                using (Stream outputStream = File.OpenWrite(fileName)) 
                { 
                    byte[] buffer = new byte[4096]; 
                    int bytesRead; 
                    do 
                    { 
                        bytesRead = inputStream.Read(buffer, 0, buffer.Length); 
                        currentIndex += bytesRead; 
                        double percentage = (double)currentIndex / contentLength; 
                        if (splash != null) 
                        { 
                            if (!splash.IsDisposed) 
                                splash.UpdateProgressBar((int)(percentage * 100)); 
                        } 
                        outputStream.Write(buffer, 0, bytesRead); 
                    } while (bytesRead != 0); 
                    if (splash != null) 
                    { 
                        if (!splash.IsDisposed) 
                        { 
                            splash.UpdateProgressBar(100); 
                        } 
                    } 
                } 
 
            } 
            else 
            { 
                timer1.Stop(); 
                timer3.Start(); 
            } 
            if (splash == null) 
                FinishWebRequest(); 
        } 

异常在线:

bytesRead = inputStream.Read(buffer, 0, buffer.Length); 

异常是:WebException

操作超时

我看到异常发生时变量 bytesRead 的值为 1360 缓冲区值为 4096

System.Net.WebException occurred 
  HResult=-2146233079 
  Message=The operation has timed out. 
  Source=System 
  StackTrace: 
       at System.Net.ConnectStream.Read(Byte[] buffer, Int32 offset, Int32 size) 
       at mws.Form1.fileDownloadRadar(String uri, String fileName) in d:\C-Sharp\Download File\Downloading-File-Project-Version-012\Downloading File\Form1.cs:line 914 
  InnerException:  

第 914 行是:

bytesRead = inputStream.Read(buffer, 0, buffer.Length); 

也许我应该把 try and catch 放在某个地方?

我的代码正在下载一个文件,然后计时器开始运行,当计时器计时 5 分钟时,它会再次下载同一个文件,依此类推,我会每 5 分钟不间断地调用此方法来下载文件。

编辑这是我根据答案更改后的代码:

HttpWebRequest request; 
        int currentIndex = 0; 
        void fileDownloadRadar(string uri, string fileName) 
        { 
            if (splash != null) 
            { 
                if (!splash.IsDisposed) 
                    splash.UpdateProgressBar(0); 
            } 
            try 
            { 
                request = (System.Net.HttpWebRequest)System.Net.WebRequest.Create(uri); 
                request.Timeout = 10000; 
                request.CookieContainer = new CookieContainer(); 
                request.AllowAutoRedirect = true; 
                using (HttpWebResponse response = (HttpWebResponse)request.GetResponse()) 
                { 
                    long contentLength = response.ContentLength; 
                    if (response.ContentType == "") 
                    { 
                        Logger.Write("ContentType is Empty download was not fine !!!!!"); 
                    } 
                    if ((response.StatusCode == HttpStatusCode.OK || 
                        response.StatusCode == HttpStatusCode.Moved || 
                        response.StatusCode == HttpStatusCode.Redirect) && 
                        response.ContentType.StartsWith("image", StringComparison.OrdinalIgnoreCase)) 
                    { 
                        Logger.Write("ContentType is not empty meaning download is fine"); 
                        using (Stream inputStream = response.GetResponseStream()) 
                        using (Stream outputStream = File.OpenWrite(fileName)) 
                        { 
                            byte[] buffer = new byte[4096]; 
                            int bytesRead; 
                            do 
                            { 
                                bytesRead = inputStream.Read(buffer, 0, buffer.Length); 
                                currentIndex += bytesRead; 
                                double percentage = (double)currentIndex / contentLength; 
                                if (splash != null) 
                                { 
                                    if (!splash.IsDisposed) 
                                        splash.UpdateProgressBar((int)(percentage * 100)); 
                                } 
                                outputStream.Write(buffer, 0, bytesRead); 
                            } while (bytesRead != 0); 
                            if (splash != null) 
                            { 
                                if (!splash.IsDisposed) 
                                { 
                                    splash.UpdateProgressBar(100); 
                                } 
                            } 
                        } 
 
                    } 
                    else 
                    { 
                        timer1.Stop(); 
                        timer3.Start(); 
                    } 
                    if (splash == null) 
                        FinishWebRequest(); 
                } 
            } 
            catch (WebException ex) 
            { 
                if (ex.Status == WebExceptionStatus.Timeout) 
                { 
                    Logger.Write(ex.Status.ToString()); 
                } 
            } 
        } 

但是在它正常工作了大概一个小时左右并下载了几次文件之后,我又遇到了异常超时:

操作超时

这次上线:

using (HttpWebResponse response = (HttpWebResponse)request.GetResponse()) 

异常信息:

System.Net.WebException occurred 
  HResult=-2146233079 
  Message=The operation has timed out 
  Source=System 
  StackTrace: 
       at System.Net.HttpWebRequest.GetResponse() 
       at mws.Form1.fileDownloadRadar(String uri, String fileName) in d:\C-Sharp\Download File\Downloading-File-Project-Version-012\Downloading File\Form1.cs:line 899 
  InnerException: 

我更改了响应并使用 using 还添加了:request.Timeout = 10000; 并添加了 try and catch。

请您参考如下方法:

您看到的超时是由 ServicePointManager 引起的- 管理 ServicePoint 集合的类为 HTTP 连接提供连接管理的对象。

简而言之,无论何时创建请求和响应,重要的是调用响应对象的 Close() 方法。否则,它将阻止 ServicePoint 对象中的任何连接被释放,因此在某些时候,在您发出了临界数量的请求后,无法处理其他请求,您将遇到超时。

有关更深入的信息,请查看这篇文章:http://blogs.msdn.com/b/jpsanders/archive/2009/05/20/understanding-maxservicepointidletime-and-defaultconnectionlimit.aspx

HttpWebRequest req = CreateRequest(); 
HttpWebResponse res = req.GetResponse() as HttpWebResponse; 
... 
res.Close();  //you should always close the response 

编辑:

正如@Kevin 在评论中所说,另一种解决方案是将响应包装在 using 语句中,这将自动关闭连接:

using(HttpWebResponse res = req.GetResponse() as HttpWebResponse) 
{ 
    ... 
}