2011-09-05 12 views
8

Tengo un método (a continuación) que tira hacia abajo y devuelve el origen de una página web como una cadena. Todo funciona bien, pero cuando la conexión se agota, el programa lanza una excepción y sale. ¿Existe un método mejor para hacer esto que le permita volver a intentar el tiempo de espera, o hay una forma de hacerlo dentro de este método?Vuelva a intentar una conexión en el tiempo de espera en Java

public static String getPage(String theURL) { 
    URL url = null; 
    try { 
     url = new URL(theURL); 
    } catch (MalformedURLException e) { 
     // TODO Auto-generated catch block 
     e.printStackTrace(); 
     exitprint(); 
    } 
    InputStream is = null; 
    try { 
     is = url.openStream(); 
    } catch (IOException e) { 
     // TODO Auto-generated catch block 
     e.printStackTrace(); 
     exitprint(); 
    } 
    int ptr = 0; 
    StringBuffer buffer = new StringBuffer(); 
    try { 
     while ((ptr = is.read()) != -1) { 
      buffer.append((char)ptr); 
     } 
    } catch (IOException e) { 
     // TODO Auto-generated catch block 
     e.printStackTrace(); 
     exitprint(); 
    } 

    return buffer.toString(); 
} 

Respuesta

7

Aquí hay una refactorización del código que debe intentar la descarga N veces. Sin embargo, no lo han probado, pero debería iniciarlo en la dirección correcta.

public static String getPage(String theURL) { 

    URL url = null; 
    try { 
     url = new URL(theURL); 
    } catch (MalformedURLException e) { 
     e.printStackTrace(); 
     exitprint(); 
    } 

    for (int i = 0; i < N; i++) { 

     try { 
      InputStream is = url.openStream(); 

      int ptr = 0; 
      StringBuffer buffer = new StringBuffer(); 

      while ((ptr = is.read()) != -1) 
       buffer.append((char)ptr); 

     } catch (IOException e) { 
      continue; 
     } 

     return buffer.toString(); 
    } 

    throw new SomeException("Failed to download after " + N + " attepmts"); 
} 
+0

Gracias! Definitivamente me puso en el camino correcto. El único problema con el que me encontré fue que el búfer estaba fuera de alcance en la declaración de devolución, así que lo mantuve al pie de la declaración while, antes del catch. – InsanityOnABun

+0

Es posible que también desee verificar el código de respuesta HTTP. url.getResponseCode(); –

1

Escriba una función de envoltura a su alrededor y permita que la excepción de conexión se propague. Luego puede hacer un bucle llamando a su función existente mientras recibe la excepción de conexión hasta algunos reintentos máximos.

Esto es mejor que insertar un bucle for en su función existente porque lógicamente separa la lógica de reintento del código de línea principal. Y es más fácil de leer y entender como resultado.

1

se puede poner todo el asunto en un bucle while:

while (true) { 

    try { 
    ... 
    } catch (IOException e) { 
    continue; 
    } 

    return buffer.toString(); 
} 

La declaración return le salir del bucle. También es posible que desee realizar un seguimiento del número de intentos y detenerse después de 5-10, por cortesía, pero esa es la forma básica de la misma.

Editar

La versión mejor, basado en los comentarios:

int retries = 10; 
for (int i = 0 ; i < retries ; i++) { 

    try { 
    ... 
    } catch (IOException e) { 
    continue; 
    } 

    return buffer.toString(); 
} 
+1

o usa un 'for' para dejar en claro que se trata de un reintento limitado? De todos modos, +1 para "cortesía" :-) – fvu

+0

Oh, sí, sí. A algunas personas les gusta usar 'for' para solo enlazar una cierta cantidad de veces: P – andronikus

1

En lugar de

try { 
    is = url.openStream(); 
} catch (IOException e) { 
    // TODO Auto-generated catch block 
    e.printStackTrace(); 
    exitprint(); 
} 

puede intentar establecer el tiempo de espera más largo y todavía se puede manejar excepción de tiempo de espera por la captura it

try { 
    URLConnection con= url.openConnection(); 
    con.setConnectTimeout(5000); 
    con.setReadTimeout(50000); 
    BufferedReader in = new BufferedReader(
     new InputStreamReader(con.getInputStream())); 
    String inputLine; 
    while ((inputLine = in.readLine()) != null) 
     System.out.println(inputLine); 
    in.close(); 
} catch (SocketTimeoutException e) { 
    //here you can still handle timeout like try again under certain conditions 
} 
1

Creo que las anotaciones AOP y Java son una buena opción. Yo recomendaría utilizar un mecanismo de lectura de jcabi-aspects:

@RetryOnFailure(attempts = 2, delay = 10) 
public String load(URL url) { 
    return url.openConnection().getContent(); 
} 
Cuestiones relacionadas