j'ai écrit une simple fonction C # pour récupérer l'historique des transactions de MtGox avec l'appel suivant:
https://data.mtgox.com/api/1/BTCUSD/trades?since=<trade_id>
documenté ici: https://en.bitcoin.it/wiki/MtGox/API/HTTP/v1#Multi_currency_trades
voici la fonction:
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;
}
je commence à tid = 0 (identifiant de commerce) pour obtenir les données (depuis le début). pour chaque demande, je reçois une réponse contenant 1000 informations sur les échanges. J'envoie toujours le Trade ID de la réponse précédente pour la prochaine demande. cela fonctionne bien pour exactement 4 demandes et réponses. mais après cela, la ligne suivante génère une "System.Net.WebException", indiquant que "l'opération a expiré":
HttpWebResponse response = (HttpWebResponse)request.GetResponse();
voici les faits:
des idées de ce qui pourrait être faux?
Il existe deux types de délais d'attente. Délai d'expiration du client et du serveur. Avez-vous essayé de faire quelque chose comme ça:
request.Timeout = Timeout.Infinite;
request.KeepAlive = true;
Essayez quelque chose comme ça ...
J'avais le même problème… .. Pour moi, le correctif était aussi simple que d'envelopper le code HttpWebResponse en utilisant block.
using (HttpWebResponse response = (HttpWebResponse) request.GetResponse())
{
// Do your processings here....
}
Détails : Ce problème se produit généralement lorsque plusieurs demandes sont adressées au même hôte et que WebResponse
n'est pas éliminé correctement. C’est là que le bloc using
éliminera correctement l’objet WebResponse
et résoudra ainsi le problème.
J'ai eu des problèmes similaires en appelant un service REST sur un serveur LINUX via SSL. Après avoir essayé de nombreux scénarios de configuration, j'ai découvert que je devais envoyer un UserAgent dans la tête http.
Voici ma dernière méthode pour appeler l'API REST.
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;
}
}
Pour ce que ça vaut, je rencontrais les mêmes problèmes avec les délais d'attente chaque fois que je l'utilisais, même si des appels étaient acheminés vers le serveur que j'appelais. Le problème dans mon cas était que j'avais Expect réglé sur application/json, alors que ce n'était pas ce que le serveur retournait.
Ce n'est pas une solution, mais simplement une alternative: Ces jours-ci, j'utilise presque uniquement WebClient au lieu de HttpWebRequest. En particulier WebClient.UploadString pour POST et PUT et WebClient.DownloadString. Ceux-ci prennent simplement et retournent des chaînes. De cette façon, je n'ai pas à traiter avec les objets de flux, sauf lorsque je reçois une exception WebException. Je peux également définir le type de contenu avec WebClient.Headers ["Content-type"] si nécessaire. La déclaration using facilite également la vie en appelant Dispose pour moi.
Rarement pour la performance, j'attribue une valeur élevée à System.Net.ServicePointManager.DefaultConnectionLimit et j'utilise plutôt HttpClient avec ses méthodes Async pour des appels simultanés.
Voilà comment je le ferais maintenant
string GetTradesOnline(Int64 tid)
{
using (var wc = new WebClient())
{
return wc.DownloadString("https://data.mtgox.com/api/1/BTCUSD/trades?since=" + tid.ToString());
}
}
2 autres exemples 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;
}
La gestion des erreurs
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);
throw; // re-throw without changing the stack trace
}