HttpURLConnection timeout settings

123

Quiero devolver false si la URL tarda más de 5 segundos en conectarse; ¿cómo es esto posible con Java? Aquí está el código que estoy usando para verificar si la URL es válida

HttpURLConnection.setFollowRedirects(false);
HttpURLConnection con = (HttpURLConnection) new URL(url).openConnection();
con.setRequestMethod("HEAD");
return (con.getResponseCode() == HttpURLConnection.HTTP_OK);
Malaquías
fuente

Respuestas:

201

HttpURLConnectiontiene un método setConnectTimeout .

Simplemente configure el tiempo de espera en 5000 milisegundos y luego capture java.net.SocketTimeoutException

Su código debería verse así:


try {
   HttpURLConnection.setFollowRedirects(false);
   HttpURLConnection con = (HttpURLConnection) new URL(url).openConnection();
   con.setRequestMethod("HEAD");

   con.setConnectTimeout(5000); //set timeout to 5 seconds

   return (con.getResponseCode() == HttpURLConnection.HTTP_OK);
} catch (java.net.SocketTimeoutException e) {
   return false;
} catch (java.io.IOException e) {
   return false;
}


dbyrne
fuente
3
Configuré el valor en 10 minutos. Sin embargo, me arroja un poco java.net.ConnectException: Connection timed out: connectantes de que transcurran 2 minutos. ¿Sabes qué está causando el problema?
Pacerier
55
SocketTimeoutException es una subclase de IOException. Si ambos bloques de captura hacen lo mismo, podría capturar IOException.
spaaarky21
2
@ spaaarky21 es correcto. Sin embargo, si está creando una IU y desea notificar a sus usuarios que se produjo un tiempo de espera, debe detectar SocketTimeoutException antes de IOException; de lo contrario, no se podrá acceder.
Clocker
3
NB !!! debe llamar setConnectTimeoutantes que cualquiera de los métodos que se conectan implícitamente (básicamente todos los métodos que arrojan IllegalStateException si ya están conectados). Idealmente, haga que setConnectTimeout (readTimeout) sea el primer método llamado.
Adam Gent
44
No me funcionó. Pero, después de agregar con.setReadTimeout(), funcionó como se esperaba.
Paulo
115

Puede configurar el tiempo de espera de esta manera,

con.setConnectTimeout(connectTimeout);
con.setReadTimeout(socketTimeout);
Codificador ZZ
fuente
2
¿Cuál es el valor máximo del tiempo de espera que podemos especificar?
Pacerier
77
@Pacerier Los documentos no indican esto explícitamente. Lanza una IllegalArgumentException si el valor es negativo (un valor de 0 significaría esperar indefinidamente). Dado que el tiempo de espera es de 32 bits int sin signo, supongo que el tiempo de espera máximo sería de aproximadamente 49 días (aunque dudo seriamente que este valor sea útil para cualquiera).
Jay Sidri
1

Si la conexión HTTP no agota el tiempo de espera, puede implementar el comprobador de tiempo de espera en el propio subproceso en segundo plano (AsyncTask, Service, etc.), la siguiente clase es un ejemplo para Customize AsyncTask que agota el tiempo de espera después de cierto período

public abstract class AsyncTaskWithTimer<Params, Progress, Result> extends
    AsyncTask<Params, Progress, Result> {

private static final int HTTP_REQUEST_TIMEOUT = 30000;

@Override
protected Result doInBackground(Params... params) {
    createTimeoutListener();
    return doInBackgroundImpl(params);
}

private void createTimeoutListener() {
    Thread timeout = new Thread() {
        public void run() {
            Looper.prepare();

            final Handler handler = new Handler();
            handler.postDelayed(new Runnable() {
                @Override
                public void run() {

                    if (AsyncTaskWithTimer.this != null
                            && AsyncTaskWithTimer.this.getStatus() != Status.FINISHED)
                        AsyncTaskWithTimer.this.cancel(true);
                    handler.removeCallbacks(this);
                    Looper.myLooper().quit();
                }
            }, HTTP_REQUEST_TIMEOUT);

            Looper.loop();
        }
    };
    timeout.start();
}

abstract protected Result doInBackgroundImpl(Params... params);
}

Una muestra para esto

public class AsyncTaskWithTimerSample extends AsyncTaskWithTimer<Void, Void, Void> {

    @Override
    protected void onCancelled(Void void) {
        Log.d(TAG, "Async Task onCancelled With Result");
        super.onCancelled(result);
    }

    @Override
    protected void onCancelled() {
        Log.d(TAG, "Async Task onCancelled");
        super.onCancelled();
    }

    @Override
    protected Void doInBackgroundImpl(Void... params) {
        // Do background work
        return null;
    };
 }
Ayman Mahgoub
fuente
Es absolutamente innecesario crear un nuevo hilo looper solo para programar una llamada para cancelar (). Puedes hacerlo desde el hilo principal onPreExecute(). Además, si cancela la tarea manualmente, también debe cancelar la llamada programada para evitar fugas.
BladeCoder
El punto aquí es cancelar AsyncTask en el medio de doInBackground () cuando toma demasiado tiempo en la ejecución, no en onPreExecute (), también quiero cancelar solo esta instancia de AsyncTask que toma demasiado tiempo y mantener a los demás, lo agradezco mucho tu retroalimentación.
Ayman Mahgoub
2
Creo que mi mensaje no fue lo suficientemente claro. No dije que debería cancelar en onPreExecute (), dije que debería crear el controlador en onPreExecute () y publicar la cancelación retrasada desde el hilo principal. De esta manera, usará el hilo principal como hilo looper y, por supuesto, puede cancelar AsyncTask más tarde mientras se ejecuta doInBackground () porque el hilo principal también se ejecuta simultáneamente con el hilo de fondo.
BladeCoder
-1

Podría obtener una solución para un problema tan similar con la adición de una línea simple

HttpURLConnection hConn = (HttpURLConnection) url.openConnection();
hConn.setRequestMethod("HEAD");

Mi requisito era conocer el código de respuesta y para eso solo obtener la metainformación era suficiente, en lugar de obtener el cuerpo de respuesta completo.

El método de solicitud predeterminado es GET y eso tardó mucho tiempo en regresar, finalmente arrojándome SocketTimeoutException. La respuesta fue bastante rápida cuando configuré el Método de solicitud en HEAD.

Subrata Nath
fuente
1
Esta no es de ninguna manera la solución, está cambiando el método de solicitud a una HEADsolicitud que no producirá ningún cuerpo de respuesta.
Sveinung Kval Bakken
Esto no agrega nada a la pregunta original. OP tiene .setRequestMethod("HEAD")en su código. Curiosamente, esta descripción fue exactamente lo que necesitaba para reducir mi problema de "Demasiados archivos abiertos". ¿Así que gracias?
Joshua Pinter el