简体   繁体   English

HttpWebRequest.GetResponse() 不断超时

[英]HttpWebRequest.GetResponse() keeps getting timed out

i wrote a simple C# function to retrieve trade history from MtGox with following API call:我编写了一个简单的 C# 函数,通过以下 API 调用从 MtGox 检索交易历史:

https://data.mtgox.com/api/1/BTCUSD/trades?since=<trade_id>

documented here: https://en.bitcoin.it/wiki/MtGox/API/HTTP/v1#Multi_currency_trades此处记录: https : //en.bitcoin.it/wiki/MtGox/API/HTTP/v1#Multi_currency_trades

here's the function:这是功能:

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;
}

i'm starting at tid=0 (trade id) to get the data (from the very beginning).我从 tid=0 (trade id) 开始获取数据(从一开始)。 for each request, i receive a response containing 1000 trade details.对于每个请求,我都会收到一个包含 1000 个交易详细信息的响应。 i always send the trade id from the previous response for the next request.对于下一个请求,我总是从上一个响应中发送交易 ID。 it works fine for exactly 4 requests & responses.它正好适用于 4 个请求和响应。 but after that, the following line throws a "System.Net.WebException", saying that "The operation has timed out":但在那之后,以下行抛出“System.Net.WebException”,表示“操作已超时”:

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

here are the facts:以下是事实:

  • catching the exception and retying keeps causing the same exception捕获异常并重新绑定不断导致相同的异常
  • the default HttpWebRequest .Timeout and .ReadWriteTimeout are already high enough (over a minute)默认的 HttpWebRequest .Timeout 和 .ReadWriteTimeout 已经足够高(超过一分钟)
  • changing HttpWebRequest.KeepAlive to false didn't solve anything either将 HttpWebRequest.KeepAlive 更改为 false 也没有解决任何问题
  • it seems to always work in the browser even while the function is failing即使功能失败,它似乎总是在浏览器中工作
  • it has no problems retrieveing the response from https://www.google.comhttps://www.google.com检索响应没有问题
  • the amount of successful responses before the exceptions varies from day to day (but browser always works)异常之前的成功响应数量每天都在变化(但浏览器始终有效)
  • starting at the trade id that failed last time causes the exception immediately从上次失败的交易 ID 开始立即导致异常
  • calling this function from the main thread instead still caused the exception从主线程调用此函数仍然导致异常
  • running it on a different machine didn't work在另一台机器上运行它不起作用
  • running it from a different IP didn't work从不同的 IP 运行它不起作用
  • increasing Thread.Sleep inbetween requests does not help在请求之间增加 Thread.Sleep 没有帮助

any ideas of what could be wrong?关于什么可能是错误的任何想法?

I had the very same issue.我有同样的问题。 For me the fix was as simple as wrapping the HttpWebResponse code in using block.对我来说,修复就像在 using 块中包装 HttpWebResponse 代码一样简单。

using (HttpWebResponse response = (HttpWebResponse) request.GetResponse())
{
    // Do your processings here....
}

Details : This issue usually happens when several requests are made to the same host, and WebResponse is not disposed properly.详细信息:当对同一主机发出多个请求并且WebResponse未正确处理时,通常会发生此问题。 That is where using block will properly dispose the WebResponse object properly and thus solving the issue.这就是using块将正确处理WebResponse对象并从而解决问题的地方。

There are two kind of timeouts.有两种超时。 Client timeout and server timeout.客户端超时和服务器超时。 Have you tried doing something like this:你有没有试过做这样的事情:

request.Timeout = Timeout.Infinite;
request.KeepAlive = true;

Try something like this...尝试这样的事情......

I just had similar troubles calling a REST Service on a LINUX Server thru ssl.我只是在通过 ssl 在 LINUX 服务器上调用 REST 服务时遇到了类似的麻烦。 After trying many different configuration scenarios I found out that I had to send a UserAgent in the http head.在尝试了许多不同的配置方案后,我发现我必须在 http 头中发送一个 UserAgent。

Here is my final method for calling the REST API.这是我调用 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;
        }
    }

This is not a solution, but just an alternative: These days i almost only use WebClient instead of HttpWebRequest.这不是解决方案,而只是替代方案:这些天我几乎只使用 WebClient 而不是 HttpWebRequest。 Especially WebClient.UploadString for POST and PUT and WebClient.DownloadString.尤其是用于 POST 和 PUT 的 WebClient.UploadString 和 WebClient.DownloadString。 These simply take and return strings.这些只是获取和返回字符串。 This way i don't have to deal with streams objects, except when i get a WebException.这样我就不必处理流对象,除非我得到一个 WebException。 i can also set the content type with WebClient.Headers["Content-type"] if necessary.如有必要,我还可以使用 WebClient.Headers["Content-type"] 设置内容类型。 The using statement also makes life easier by calling Dispose for me. using 语句还通过为我调用 Dispose 使生活更轻松。

Rarely for performance, i set System.Net.ServicePointManager.DefaultConnectionLimit high and instead use HttpClient with it's Async methods for simultaneous calls.很少为了性能,我将 System.Net.ServicePointManager.DefaultConnectionLimit 设置为高,而是使用 HttpClient 及其异步方法进行同步调用。

This is how i would do it now这就是我现在要做的

string GetTradesOnline(Int64 tid)
{
    using (var wc = new WebClient())
    {
        return wc.DownloadString("https://data.mtgox.com/api/1/BTCUSD/trades?since=" + tid.ToString());
    }
}

2 more POST examples还有 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;
}

Error handling错误处理

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);
}

For what it's worth, I was experiencing the same issues with timeouts every time I used it, even though calls went through to the server I was calling.对于它的价值,我每次使用它时都会遇到相同的超时问题,即使调用通过了我正在调用的服务器。 The problem in my case was that I had Expect set to application/json, when that wasn't what the server was returning.我的问题是我将 Expect 设置为 application/json,而这不是服务器返回的内容。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM