如何在执行Web请求时指定仅连接超时?

时间:2014-11-16 22:08:04

标签: c# httpwebrequest dotnet-httpclient

我目前正在使用使用HttpClient类发出HTTP请求的代码。虽然您可以为请求指定超时,但该值适用于整个请求(包括解析主机名,建立连接,发送请求和接收响应)。

如果无法解析名称或建立连接,我需要一种方法让请求快速失败,但我有时也需要接收大量数据,因此不能只是减少超时。

有没有办法使用内置(BCL)类或备用HTTP客户端堆栈实现此目的?

我已经简要地看了一下RestSharp和ServiceStack,但似乎都没有为连接部分提供超时(但如果我错了,请纠正我)。

7 个答案:

答案 0 :(得分:5)

如果连接花费太多时间,您可以使用Timer中止请求。在经过时间后添加事件。你可以使用这样的东西:

static WebRequest request;
private static void sendAndReceive()
{
    // The request with a big timeout for receiving large amout of data
    request = HttpWebRequest.Create("http://localhost:8081/index/");
    request.Timeout = 100000;

    // The connection timeout
    var ConnectionTimeoutTime = 100;
    Timer timer = new Timer(ConnectionTimeoutTime);
    timer.Elapsed += connectionTimeout;
    timer.Enabled = true;

    Console.WriteLine("Connecting...");
    try
    {
        using (var stream = request.GetRequestStream())
        {
            Console.WriteLine("Connection success !");
            timer.Enabled = false;

            /*
             *  Sending data ...
             */
            System.Threading.Thread.Sleep(1000000);
        }

        using (var response = (HttpWebResponse)request.GetResponse())
        {
            /*
             *  Receiving datas...
             */
        }
    }
    catch (WebException e)
    {
        if(e.Status==WebExceptionStatus.RequestCanceled) 
            Console.WriteLine("Connection canceled (timeout)");
        else if(e.Status==WebExceptionStatus.ConnectFailure)
            Console.WriteLine("Can't connect to server");
        else if(e.Status==WebExceptionStatus.Timeout)
            Console.WriteLine("Timeout");
        else
            Console.WriteLine("Error");
    }
}

static void connectionTimeout(object sender, System.Timers.ElapsedEventArgs e)
{
    Console.WriteLine("Connection failed...");
    Timer timer = (Timer)sender;
    timer.Enabled = false;

    request.Abort();
}

这里的时间只是例如,你必须根据自己的需要进行调整。

答案 1 :(得分:2)

.NET的HttpWebRequest公开了2个属性,用于指定与远程HTTP服务器连接的超时:

  • Timeout - 获取或设置GetResponse和GetRequestStream方法的超时值(以毫秒为单位)。
  • ReadWriteTimeout - 写入或读取超时前的毫秒数。默认值为300,000毫秒(5分钟)。

Timeout属性最接近您所追求的属性,但它确实表明无论超时值如何,DNS解析最多可能需要15秒:

  

域名系统(DNS)查询最多可能需要15秒才能返回或超时。如果您的请求包含需要解析的主机名,并且您将Timeout设置为小于15秒的值,则可能需要15秒或更长时间才会抛出WebException以指示请求超时。

为DNS查找提取低于15秒的超时的一种方法是lookup the hostname yourself,但许多解决方案需要P / Invoke来指定低级设置。

在ServiceStack HTTP客户端中指定超时

还可以在ServiceStack的高级HTTP客户端中指定基础HttpWebRequest 超时 ReadWriteTimeout 属性,即在C# Service Clients中使用:< / p>

var client = new JsonServiceClient(BaseUri) {
    Timeout = TimeSpan.FromSeconds(30)
};

或使用ServiceStack的HTTP Utils

var timeoutMs = 30 * 1000;
var response = url.GetStringFromUrl(requestFilter: req => 
    req.Timeout = timeoutMs);

答案 2 :(得分:1)

我相信RestSharp在RestClient中确实有超时属性。

        var request = new RestRequest();
        var client = new RestClient
        {
            Timeout = timeout, //Timeout in milliseconds to use for requests made by this client instance
            ReadWriteTimeout = readWriteTimeout //The number of milliseconds before the writing or reading times out.
        };

        var response = client.Execute(request);
        //Handle response

答案 3 :(得分:0)

你没错,你无法设置这个特定的超时。 我没有足够的信息来了解这些库是如何构建的,但是出于它们的目的,我相信它们是合适的。有人想做一个请求并为所有事情设置超时。

我建议你采取不同的方法。 你试图在HttpRequest同时做两件不同的事情:

  1. 尝试找到主机/ stabblish连接;
  2. 传输数据;
  3. 您可以尝试将其分为两个阶段。

    1. 使用Ping类(check this out)尝试访问主机并为其设置超时时间;
    2. 使用适合您需要的HttpRequest IF (超时,
    3. 这个过程不应该减慢一切,因为解析名称/路线的一部分将在第一阶段完成。这不是完全一次性的。

      此解决方案存在一个缺点:您的远程主机必须接受ping。 希望这会有所帮助。

答案 4 :(得分:0)

我使用此方法检查是否可以建立连接。但是,这并不能保证可以通过HttpWebRequest中的后续呼叫建立连接。

private static bool CanConnect(string machine)
{
    using (TcpClient client = new TcpClient())
    {
        if (!client.ConnectAsync(machine, 443).Wait(50)) // Check if we can connect in 50ms
        {
            return false;
        }
    }

    return true;
}

答案 5 :(得分:-1)

如果超时不符合您的需要 - 请勿使用它们。您可以使用等待操作完成的处理程序。当你得到一个回应 - 停止处理程序并继续。这样,当失败和长时间请求大量数据时,您将获得短时间请求。

这样的事情可能是:

 var handler = new ManualResetEvent(false);

 request = (HttpWebRequest)WebRequest.Create(url)
 {
    // initialize parameters such as method
 }

 request.BeginGetResponse(new AsyncCallback(delegate(IAsyncResult result)
 {
      try
      {
          var request = (HttpWebRequest)result.AsyncState;

          using (var response = (HttpWebResponse)request.EndGetResponse(result))
          {
              using (var stream = response.GetResponseStream())
              {
                  // success 
              }

              response.Close();
          }
      }
      catch (Exception e)
      {
          // fail operations go here
      }
      finally
      {
          handler.Set(); // whenever i succeed or fail
      }
 }), request);

 handler.WaitOne(); // wait for the operation to complete

答案 6 :(得分:-1)

如果首先只询问标题,那么如果成功请求通常的资源

webRequest.Method = "HEAD";