2012-05-11 19 views
51

Tengo un servicio web que acepta un método POST con XML. Está funcionando bien y luego, en alguna ocasión aleatoria, no puede comunicarse con el servidor lanzando IOException con el mensaje The target server failed to respond. Las siguientes llamadas funcionan bien.Apache HttpClient Error interino: NoHttpResponseException

Ocurre sobre todo cuando hago algunas llamadas y luego dejo mi aplicación inactiva durante 10-15 min. la primera llamada que hago después devuelve este error.

Probé par de cosas ...

puedo configurar el controlador de reintento como

HttpRequestRetryHandler retryHandler = new HttpRequestRetryHandler() { 

      public boolean retryRequest(IOException e, int retryCount, HttpContext httpCtx) { 
       if (retryCount >= 3){ 
        Logger.warn(CALLER, "Maximum tries reached, exception would be thrown to outer block"); 
        return false; 
       } 
       if (e instanceof org.apache.http.NoHttpResponseException){ 
        Logger.warn(CALLER, "No response from server on "+retryCount+" call"); 
        return true; 
       } 
       return false; 
      } 
     }; 

     httpPost.getParams().setParameter(HttpMethodParams.RETRY_HANDLER, retryHandler); 

pero esto nunca llegó retey llamados. (sí, estoy usando la cláusula right instanceof). Mientras se depura esta clase, nunca se llama.

Incluso intenté configurar HttpProtocolParams.setUseExpectContinue(httpClient.getParams(), false); pero no uso. ¿Puede alguien sugerir qué puedo hacer ahora?

IMPORTANTE Aparte de determinar por qué estoy recibiendo excepción, uno de los más importante preocupación que tengo es por qué no se la retryhandler trabajando aquí?

+0

no creo que es algo con código de cliente. ¿Puede ser que el servidor de destino esté demasiado ocupado manejando las respuestas? – kosa

+0

Intenté fiddler para bombardear el servidor de destino, pero funcionó bien. Incluso traté de ejecutar los mismos pasos para reproducir el error utilizando el violín, ¡pero no tuve suerte! –

+0

¿Qué tipo de servidor web está ejecutando el servicio, y durante la espera de 10-15 minutos el servicio recibe otras solicitudes o el servicio está inactivo? – Shawn

Respuesta

79

Lo más probable es que las conexiones persistentes que mantiene vivo el administrador de conexiones se vuelvan obsoletas. Es decir, el servidor de destino apaga la conexión en su extremo sin que HttpClient pueda reaccionar a ese evento, mientras la conexión está inactiva, por lo tanto, hace que la conexión se cierre a medias o quede "obsoleta". Por lo general, esto no es un problema. HttpClient emplea varias técnicas para verificar la validez de la conexión a partir del pool. Incluso si la verificación de conexión obsoleta está deshabilitada y se usa una conexión obsoleta para transmitir un mensaje de solicitud, la ejecución de la solicitud generalmente falla en la operación de escritura con SocketException y se vuelve a intentar automáticamente. Sin embargo, en algunas circunstancias, la operación de escritura puede finalizar sin excepción y la operación de lectura posterior devuelve -1 (fin del flujo). En este caso, HttpClient no tiene otra opción que suponer que la solicitud fue exitosa, pero el servidor no respondió lo más probable debido a un error inesperado en el servidor.

La forma más sencilla de remediar la situación es desalojar las conexiones caducadas y las conexiones que han estado inactivas durante más de, por ejemplo, 1 minuto desde el grupo después de un período de inactividad. Para más detalles, consulte this section of the HttpClient tutorial.

+0

Estoy usando HTTTPClient 4.5.1, aquí dos servidores de reintento continuo no respondieron, pero la tercera vez lo logró, así que ¿por qué no se conecta en el primer intento? Incluso mantuve el tiempo 1 minuto como se mencionó. –

+0

@oleg, ¿Cuál es la diferencia entre conexiones inactivas y expiradas? – Ales

+1

Algunas conexiones pueden tener un tiempo de caducidad más allá del cual deben considerarse ya no válidas/reutilizables. Las conexiones inactivas son perfectamente válidas y reutilizables, pero momentáneamente no se utilizan. – oleg

10

La respuesta aceptada es correcta pero carece de solución. Para evitar este error, puede agregar setHttpRequestRetryHandler (o setRetryHandler for apache components 4.4) para su cliente HTTP como en this answer.

+1

Dado que la pregunta original especifica un POST, ¿es el manejador de reintento el enfoque correcto aquí? –

0

HttpClient 4.4 sufrió un error en esta área relacionado con la validación de posibles conexiones obsoletas antes de volver al solicitante. Es no validar si una conexión era obsoleto, y esto resulta en un NoHttpResponseException inmediato.

Este problema se resolvió en HttpClient 4.4.1. Ver this JIRA y release notes

+0

Estoy usando la versión 4.5.3, pero sigo recibiendo ** NoHttpResponseException **. En mi caso, recibo esta excepción en cada cuarta o quinta solicitud continua que no esté en la primera solicitud. ¿Alguna idea de cuál podría ser el motivo en mi caso? –

1

Hoy en día, la mayoría de las conexiones HTTP son considered persistent unless declared otherwise. Sin embargo, para guardar los recursos del servidor la conexión rara vez se mantiene abierta para siempre, el tiempo de espera de conexión predeterminado para muchos servidores es bastante corto, por ejemplo, 5 segundos para Apache httpd 2.2 y superior.

El error org.apache.http.NoHttpResponseException proviene muy probablemente de una conexión persistente que fue cerrada por el servidor.

Es posible establecer el tiempo máximo para mantener abiertas las conexiones no utilizadas en el grupo de clientes Http de Apache, en milisegundos.

Con la primavera de arranque, una forma de lograr esto:

public class RestTemplateCustomizers { 
    static public class MaxConnectionTimeCustomizer implements RestTemplateCustomizer { 

     @Override 
     public void customize(RestTemplate restTemplate) { 
      HttpClient httpClient = HttpClientBuilder 
       .create() 
       .setConnectionTimeToLive(1000, TimeUnit.MILLISECONDS) 
       .build(); 

      restTemplate.setRequestFactory(
       new HttpComponentsClientHttpRequestFactory(httpClient)); 
     } 
    } 
} 

// In your service that uses a RestTemplate 
public MyRestService(RestTemplateBuilder builder) { 
    restTemplate = builder 
     .customizers(new RestTemplateCustomizers.MaxConnectionTimeCustomizer()) 
     .build(); 
} 
+0

En mi caso, recibo esta excepción en cada cuarta o quinta solicitud continua que no esté en la primera solicitud. ¿Alguna idea de cuál podría ser el motivo en mi caso? –

Cuestiones relacionadas