HttpWebRequest.GetResponse() 不断超时
Posted
技术标签:
【中文标题】HttpWebRequest.GetResponse() 不断超时【英文标题】:HttpWebRequest.GetResponse() keeps getting timed out 【发布时间】:2013-05-24 22:22:53 【问题描述】:我编写了一个简单的 C# 函数,通过以下 API 调用从 MtGox 检索交易历史记录:
https://data.mtgox.com/api/1/BTCUSD/trades?since=<trade_id>
在此处记录:https://en.bitcoin.it/wiki/MtGox/API/HTTP/v1#Multi_currency_trades
函数如下:
string GetTradesOnline(Int64 tid)
Thread.Sleep(30000);
// communicate
string url = "https://data.mtgox.com/api/1/BTCUSD/trades?since=" + tid.ToString();
HttpWebRequest request = (HttpWebRequest)WebRequest.Create(url);
HttpWebResponse response = (HttpWebResponse)request.GetResponse();
StreamReader reader = new StreamReader(response.GetResponseStream());
string json = reader.ReadToEnd();
reader.Close();
reader.Dispose();
response.Close();
return json;
我从 tid=0(交易 ID)开始获取数据(从一开始)。对于每个请求,我都会收到包含 1000 个交易详细信息的响应。我总是从上一个响应中为下一个请求发送交易 ID。它恰好适用于 4 个请求和响应。但在那之后,以下行抛出“System.Net.WebException”,表示“操作已超时”:
HttpWebResponse response = (HttpWebResponse)request.GetResponse();
以下是事实:
捕获异常并重新尝试一直导致相同的异常 默认的 HttpWebRequest .Timeout 和 .ReadWriteTimeout 已经足够高(超过一分钟) 将 HttpWebRequest.KeepAlive 更改为 false 也没有解决任何问题 即使功能失败,它似乎也始终在浏览器中工作 从https://www.google.com检索响应没有问题 异常前的成功响应数量每天都在变化(但浏览器始终有效) 从上次失败的交易 ID 开始立即导致异常 从主线程调用此函数仍会导致异常 在另一台机器上运行它不起作用 从不同的 IP 运行它不起作用 在请求之间增加 Thread.Sleep 无济于事有什么想法可能是错的吗?
【问题讨论】:
【参考方案1】:我遇到了同样的问题。 对我来说,修复就像在 using 块中包装 HttpWebResponse 代码一样简单。
using (HttpWebResponse response = (HttpWebResponse) request.GetResponse())
// Do your processings here....
详细说明:此问题通常发生在向同一主机发出多个请求且未正确处理 WebResponse
时。这就是using
块将正确处理WebResponse
对象并因此解决问题的地方。
【讨论】:
您能解释一下为什么将其包装在 using 块中会改变行为吗? 嗨@RussellMcDonnell。如果您向同一主机发出多个请求,并且WebResponse
未正确处理,通常会发生此问题。这就是为什么 using 块作为救星来到这里的原因。
伙计们,你说得对,我忘了处理我的回复。我当时应该使用 using 语句(我不知道)。我无法测试这是否会有所帮助,因为 mtgox 已经消失了。但这很可能是解决方案
虽然是老帖子,但应该标记为正确答案。
也解决了我的问题,这比公认的答案要好。我只是以为我不需要dispose,因为web请求本身没有实现IDisposable,我只是没有看响应:)【参考方案2】:
有两种超时。客户端超时和服务器超时。您是否尝试过这样做:
request.Timeout = Timeout.Infinite;
request.KeepAlive = true;
试试这样的...
【讨论】:
是的,请小心处理大量请求,因为服务器会识别到这一点并关闭流量,因为这通常是拒绝服务,它会在一段时间内阻止您的 IP 以防止黑客入侵。如果您同意,您可以点击接受吗?【参考方案3】:我刚刚通过 ssl 在 LINUX 服务器上调用 REST 服务时遇到了类似的问题。在尝试了许多不同的配置方案后,我发现我必须在 http 头中发送一个 UserAgent。
这是我调用 REST API 的最终方法。
private static string RunWebRequest(string url, string json)
HttpWebRequest request = (HttpWebRequest)WebRequest.Create(url);
// Header
request.ContentType = "application/json";
request.Method = "POST";
request.AllowAutoRedirect = false;
request.KeepAlive = false;
request.Timeout = 30000;
request.ReadWriteTimeout = 30000;
request.UserAgent = "test.net";
request.Accept = "application/json";
request.ProtocolVersion = HttpVersion.Version11;
request.Headers.Add("Accept-Language","de_DE");
ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls;
ServicePointManager.ServerCertificateValidationCallback = delegate return true; ;
byte[] bytes = Encoding.UTF8.GetBytes(json);
request.ContentLength = bytes.Length;
using (var writer = request.GetRequestStream())
writer.Write(bytes, 0, bytes.Length);
writer.Flush();
writer.Close();
var httpResponse = (HttpWebResponse)request.GetResponse();
using (var streamReader = new StreamReader(httpResponse.GetResponseStream()))
var jsonReturn = streamReader.ReadToEnd();
return jsonReturn;
【讨论】:
KeepAlive = false;
?
我在过去使用服务和keepAlive =true时有过一些不好的经历。尤其是使用 SAP 后端。从那以后我设置keepAlive = false。我们松开了 tcp 套接字,但我们确信请求在双方都终止了。
我的没有关闭流写入器。谢谢。【参考方案4】:
这不是一个解决方案,而只是一个替代方案: 这些天我几乎只使用 WebClient 而不是 HttpWebRequest。特别是用于 POST 和 PUT 的 WebClient.UploadString 和 WebClient.DownloadString。这些只是获取和返回字符串。这样我就不必处理流对象,除非我得到一个 WebException。如有必要,我还可以使用 WebClient.Headers["Content-type"] 设置内容类型。 using 语句还通过为我调用 Dispose 使生活更轻松。
很少为了性能,我将 System.Net.ServicePointManager.DefaultConnectionLimit 设置为高,而是使用 HttpClient 和它的异步方法进行同时调用。
这就是我现在的做法
string GetTradesOnline(Int64 tid)
using (var wc = new WebClient())
return wc.DownloadString("https://data.mtgox.com/api/1/BTCUSD/trades?since=" + tid.ToString());
另外 2 个 POST 示例
// POST
string SubmitData(string data)
string response;
using (var wc = new WebClient())
wc.Headers["Content-type"] = "text/plain";
response = wc.UploadString("https://data.mtgox.com/api/1/BTCUSD/trades", "POST", data);
return response;
// POST: easily url encode multiple parameters
string SubmitForm(string project, string subject, string sender, string message)
// url encoded query
NameValueCollection query = HttpUtility.ParseQueryString(string.Empty);
query.Add("project", project);
query.Add("subject", subject);
// url encoded data
NameValueCollection data = HttpUtility.ParseQueryString(string.Empty);
data.Add("sender", sender);
data.Add("message", message);
string response;
using (var wc = new WebClient())
wc.Headers[HttpRequestHeader.ContentType] = "application/x-www-form-urlencoded";
response = wc.UploadString( "https://data.mtgox.com/api/1/BTCUSD/trades?"+query.ToString()
, WebRequestMethods.Http.Post
, data.ToString()
);
return response;
错误处理
try
Console.WriteLine(GetTradesOnline(0));
string data = File.ReadAllText(@"C:\mydata.txt");
Console.WriteLine(SubmitData(data));
Console.WriteLine(SubmitForm("The Big Project", "Progress", "John Smith", "almost done"));
catch (WebException ex)
string msg;
if (ex.Response != null)
// read response HTTP body
using (var sr = new StreamReader(ex.Response.GetResponseStream())) msg = sr.ReadToEnd();
else
msg = ex.Message;
Log(msg);
【讨论】:
【参考方案5】:不管怎样,我每次使用它时都会遇到同样的超时问题,即使调用是通过我正在调用的服务器进行的。我的问题是我将 Expect 设置为 application/json,而这不是服务器返回的内容。
【讨论】:
以上是关于HttpWebRequest.GetResponse() 不断超时的主要内容,如果未能解决你的问题,请参考以下文章