我写了一个简单的c#函数来检索MtGox的交易历史,使用以下API调用:
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"。webeexception ",提示"操作已超时":
HttpWebResponse response = (HttpWebResponse)request.GetResponse();
事实如下:
- 捕获异常并重试一直导致相同的异常
- 默认的HttpWebRequest .Timeout和.ReadWriteTimeout已经足够高(超过一分钟)
- HttpWebRequest变化。KeepAlive到false也没有解决任何问题
- 它似乎总是在浏览器中工作,即使功能失败
- 从https://www.google.com 检索响应没有问题
- 异常前成功响应的数量每天都在变化(但浏览器总是工作)
- 从上次失败的交易id开始立即导致异常
- 从主线程调用此函数仍然会导致异常
- 在其他机器上运行不正常
- 从另一个IP运行它不起作用
- 增加线程。请求之间的睡眠没有帮助
你知道哪里出了问题吗?
我也有同样的问题。对我来说,修复是简单的包装HttpWebResponse代码在使用块。
using (HttpWebResponse response = (HttpWebResponse) request.GetResponse())
{
// Do your processings here....
}
Details:此问题通常发生在向同一主机发出多个请求并且WebResponse
未正确处理时。即using
块将正确处置WebResponse
对象,从而解决问题。
有两种超时。客户端超时和服务器超时。你试过这样做吗?
request.Timeout = Timeout.Infinite;
request.KeepAlive = true;
我刚刚在LINUX服务器上通过ssl调用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;
}
}
这不是一个解决方案,而是一个替代方案:这些天我几乎只使用WebClient而不是HttpWebRequest。尤其是WebClient。上传字符串用于POST和PUT和WebClient.DownloadString。它们只是接受并返回字符串。这样我就不必处理流对象,除非我得到一个webeexception。如果需要,我也可以使用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());
}
}
更多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);
}
无论如何,我每次使用它都会遇到同样的超时问题,即使调用经过我正在调用的服务器。在我的例子中,问题是我将Expect设置为application/json,而这不是服务器返回的内容。