Saltar al contenido

Cómo configurar HttpWebRequest.Timeout para una solicitud HTTP grande en C #

Solución:

Hay dos tiempos de espera que nos molestan al procesar la carga de un archivo grande. HttpWebRequest.Timeout y HttpWebRequest.ReadWriteTimeout. Necesitaremos abordar ambos.

HttpWebRequest.ReadWriteTimeout

Primero, abordemos HttpWebRequest.ReadWriteTimeout. Necesitamos deshabilitar el “almacenamiento en búfer de secuencia de escritura”.

httpRequest.AllowWriteStreamBuffering = false;

Con esta configuración cambiada, su HttpWebRequest.ReadWriteTimeout los valores funcionarán mágicamente como le gustaría, puede dejarlos en el valor predeterminado (5 minutos) o incluso disminuirlos. Utilizo 60 segundos.

Este problema surge porque, al cargar un archivo grande, si los datos están almacenados en búfer por .NET framework, su código pensará que la carga está terminada cuando no lo esté, y llamará HttpWebRequest.GetResponse() demasiado pronto, que se agotará.

HttpWebRequest.Timeout

Ahora, abordemos HttpWebRequest.Timeout.

Nuestro segundo problema surge porque HttpWebRequest.Timeout se aplica a toda la carga. El proceso de carga en realidad consta de tres pasos (aquí hay un gran artículo que fue mi referencia principal):

  1. Una solicitud para comienzo la carga.
  2. Escritura de los bytes.
  3. Una solicitud para terminar la carga y obtenga cualquier respuesta del servidor.

Si tenemos un tiempo de espera que se aplica a toda la carga, necesitamos una gran cantidad para acomodar la carga de archivos grandes, pero también nos enfrentamos al problema de que un tiempo de espera legítimo tardará mucho en agotarse. Esta no es una buena situacion. En cambio, queremos un breve tiempo de espera (digamos 30 segundos) para aplicar a los pasos n. ° 1 y n. ° 3. No queremos un tiempo de espera general en el n. ° 2 en absoluto, pero queremos que la carga falle si los bytes dejan de escribirse durante un período de tiempo. Afortunadamente, ya hemos abordado el n. ° 2 con HttpWebRequest.ReadWriteTimeout, solo tenemos que corregir el comportamiento molesto de HttpWebRequest.Timeout. Resulta que las versiones asincrónicas de GetRequestStream y GetResponse hacer exactamente lo que necesitamos.

Entonces quieres este código:

public static class AsyncExtensions
{
    public static Task<T> WithTimeout<T>(this Task<T> task, TimeSpan timeout)
    {
        return Task.Factory.StartNew(() =>
        {
            var b = task.Wait((int)timeout.TotalMilliseconds);
            if (b) return task.Result;
            throw new WebException("The operation has timed out", WebExceptionStatus.Timeout);
        });
    }
}

Y en lugar de llamar GetRequestStream y GetResponse llamaremos a las versiones asincrónicas:

var uploadStream = httpRequest.GetRequestStreamAsync().WithTimeout(TimeSpan.FromSeconds(30)).Result;

Y de manera similar para la respuesta:

var response = (HttpWebResponse)httpRequest.GetResponseAsync().WithTimeout(TimeSpan.FromSeconds(30)).Result;

Eso es todo lo que necesita. Ahora tus cargas serán mucho más confiables. Puede envolver toda la carga en un ciclo de reintento para mayor certeza.

¡Haz clic para puntuar esta entrada!
(Votos: 0 Promedio: 0)



Utiliza Nuestro Buscador

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *