C# 如何在C中为大型HTTP请求设置HttpWebRequest.Timeout#
我不知道如何处理HttpWebRequest.Timeout。以前,我常常直接为套接字对象设置超时:Timeout设置发送或接收数据块的最大时间。但是,HttpWebRequest.Timeout似乎设置了整个HTTP请求的超时。如果请求很大(例如,我正在用HTTP PUT上传一个大文件),可能需要几个小时。这让我想到了设置:C# 如何在C中为大型HTTP请求设置HttpWebRequest.Timeout#,c#,sockets,http,timeout,C#,Sockets,Http,Timeout,我不知道如何处理HttpWebRequest.Timeout。以前,我常常直接为套接字对象设置超时:Timeout设置发送或接收数据块的最大时间。但是,HttpWebRequest.Timeout似乎设置了整个HTTP请求的超时。如果请求很大(例如,我正在用HTTP PUT上传一个大文件),可能需要几个小时。这让我想到了设置: ... request.Timeout = System.Threading.Timeout.Infinite; Stream requestStream = reque
...
request.Timeout = System.Threading.Timeout.Infinite;
Stream requestStream = request.GetRequestStream();
for (something)
{
...
requestStream.Write(b, 0, b.Length);
}
然而,这是否意味着如果与服务器的网络连接被卡住,我将以requestStream结束。Write never抛出“操作超时”异常?所以超时的概念在这种情况下不起作用
理想情况下,我希望这样。超时设置只影响单个requestStream.Write。我可以根据需要拥有任意多个Write(),只要每个Write()的值不超过.Timeout
或者我需要实现自己的基于套接字的机制来实现这一点
另外,在设置断点时,我发现requestStream实际上是ConnectStream实例,其超时值为300000(300秒)。这难道不意味着无限实际上并不是无限的,而是被限制在300秒之内吗?对于大文件和慢速连接,这是一个相当严格的限制。最简单的方法是创建自己的类,该类继承WebRequest
public class MyRequest : WebRequest
{
public MyRequest()
{
this.Timeout = 1234;
}
}
在处理大型文件上传时,有两个超时问题困扰着我们
HttpWebRequest.Timeout
和HttpWebRequest.ReadWriteTimeout
。我们需要同时解决这两个问题
HttpWebRequest.ReadWriteTimeout
首先,让我们寻址HttpWebRequest.ReadWriteTimeout
。我们需要禁用“写流缓冲”
更改此设置后,您的HttpWebRequest.ReadWriteTimeout
值将神奇地按您所希望的方式工作,您可以将其保留在默认值(5分钟)甚至减少。我用60秒
出现此问题的原因是,在上载大文件时,如果数据由.NET framework缓冲,则代码会认为上载已完成,而不是完成,并过早调用HttpWebRequest.GetResponse()
,这将超时
HttpWebRequest.Timeout
现在,让我们寻址http://code>HttpWebRequest.Timeout
第二个问题是因为HttpWebRequest.Timeout
适用于整个上传。上载过程实际上包括三个步骤():
HttpWebRequest.ReadWriteTimeout
解决了#2问题,我们只需要修复HttpWebRequest.Timeout
的恼人行为。事实证明,GetRequestStream
和GetResponse
的异步版本正是我们所需要的
因此,您需要以下代码:
public static class AsyncExtensions
{
public static Task<T> WithTimeout<T>(this Task<T> task, TimeSpan timeout)
{
return Task.Factory.StartNew(() =>
{
var b = task.Wait((int)timeout.TotalMilliseconds);
if (b) return task.Result;
throw new WebException("The operation has timed out", WebExceptionStatus.Timeout);
});
}
}
同样,对于回应:
var response = (HttpWebResponse)httpRequest.GetResponseAsync().WithTimeout(TimeSpan.FromSeconds(30)).Result;
这就是你所需要的。现在,您的上传将更加可靠。您可以将整个上传过程包装在重试循环中,以增加确定性。请注意,对于带有mono的HttpWebRequest,这一点非常重要(如Boinst所述)
httpRequest.AllowWriteStreamBuffering=false代码>
我花了整整一天时间与Wireshark一起寻找大文件上传不成功的原因,最后偶然发现了这个简单快捷的答案。谢谢您的回复。然而,我还不明白这有什么帮助。目前,在.NET CLR中似乎存在一个bug,它使得HttpWebRequest.ReadWriteTimeout和Stream.WriteTimeout变得无用。您的解决方案如何帮助克服这一问题?经理c#不允许您访问这些属性。使用MyRequest并将代码添加到类中。不是很难。我可以设置HttpWebRequest.Timeout。直接在子类中设置相同属性的目的是什么?效果会有什么不同?
var uploadStream = httpRequest.GetRequestStreamAsync().WithTimeout(TimeSpan.FromSeconds(30)).Result;
var response = (HttpWebResponse)httpRequest.GetResponseAsync().WithTimeout(TimeSpan.FromSeconds(30)).Result;