web-dev-qa-db-fra.com

Comment puis-je spécifier un délai d'expiration de connexion uniquement lors de l'exécution de requêtes Web?

J'utilise actuellement du code qui crée des requêtes HTTP à l'aide de la classe HttpClient. Bien que vous puissiez spécifier un délai d'expiration pour la demande, la valeur s'applique à l'ensemble de la demande (ce qui inclut la résolution du nom d'hôte, l'établissement d'une connexion, l'envoi de la demande et la réception de la réponse).

J'ai besoin d'un moyen de faire en sorte que les demandes échouent rapidement si elles ne peuvent pas résoudre le nom ou établir une connexion, mais j'ai parfois aussi besoin de recevoir de grandes quantités de données. Par conséquent, je ne peux pas simplement réduire le délai d'expiration.

Y a-t-il un moyen d'y parvenir en utilisant une classe intégrée (BCL) ou une pile de clients HTTP alternative?

J'ai brièvement examiné RestSharp et ServiceStack, mais ni l'un ni l'autre ne semble fournir de délai d'expiration pour la partie connexion uniquement (mais corrigez-moi si je me trompe).

12
Morten Mertner

Vous pouvez utiliser une variable Timer pour abandonner la demande si la connexion prend trop de temps. Ajouter un événement lorsque le temps est écoulé. Vous pouvez utiliser quelque chose comme ceci:

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

Les temps ici ne sont que par exemple, vous devez les ajuster à vos besoins.

5
Ludovic Feltz

.NET's HttpWebRequest expose 2 propriétés pour spécifier un délai d'attente pour la connexion à un serveur HTTP distant:

  • Timeout - Obtient ou définit la valeur de délai d'attente en millisecondes pour les méthodes GetResponse et GetRequestStream.
  • ReadWriteTimeout - Le nombre de millisecondes avant l'expiration de l'écriture ou de la lecture. La valeur par défaut est 300 000 millisecondes (5 minutes).

La propriété Timeout est la plus proche de ce que vous recherchez, mais elle suggère que quelle que soit la valeur de délai d'attente, la résolution DNS peut prendre jusqu'à 15 secondes:

Une requête DNS (Domain Name System) peut prendre jusqu'à 15 secondes pour revenir ou expirer. Si votre demande contient un nom d'hôte qui nécessite une résolution et que vous définissez Timeout sur une valeur inférieure à 15 secondes, il peut s'écouler 15 secondes ou plus avant qu'une exception WebException soit générée pour indiquer un délai d'attente sur votre demande.

Une façon de prévoir un délai d'expiration inférieur à 15 secondes pour les recherches DNS consiste à rechercher vous-même le nom d'hôte , mais de nombreuses solutions nécessitent P/Invoke pour spécifier des paramètres de bas niveau.

Spécification des délais d'attente dans les clients HTTP ServiceStack

Les HttpWebRequest Timeout et ReadWriteTimeout sous-jacents peuvent également être spécifiés dans les clients HTTP de haut niveau de ServiceStack, c.-à-d. Dans Clients de service C # avec:

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

Ou en utilisant HTTP Utils de ServiceStack avec:

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

Je pense que RestSharp a des propriétés de délai d'expiration dans 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
1
cubski

Vous avez raison, vous ne pouvez pas définir ce délai d'expiration spécifique. Je ne dispose pas de suffisamment d'informations sur la manière dont les bibliothèques ont été construites, mais je pense qu'elles conviennent à la tâche à laquelle elles sont destinées. Quelqu'un veut faire une demande et définir un délai d'attente pour tout.

Je suggère que vous adoptiez une approche différente. Vous essayez de faire deux choses différentes ici que HttpRequest font en même temps:

  1. Essayez de trouver l’hôte/établissez une connexion;
  2. Transférer des données;

Vous pouvez essayer de séparer cela en deux étapes.

  1. Utilisez Ping class ( vérifiez ceci ) pour essayer de vous rendre chez votre hôte et définissez un délai d’expiration pour celui-ci;
  2. Utilisez la HttpRequestIFcela fonctionne pour vos besoins (de délai d’attente, 

Ce processus ne devrait pas tout ralentir car une partie de la résolution des noms/itinéraires serait effectuée à la première étape. Ce ne serait pas totalement jetable.

Cette solution présente un inconvénient: votre hôte distant doit accepter les pings. J'espère que cela vous aidera.

0
rodrigogq

J'ai utilisé cette méthode pour vérifier si la connexion peut être établie. Ceci ne permet cependant pas de garantir que la connexion peut être établie par l'appel suivant dans 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;
}
0
tcb