HttpURLConnection timeout settings


123

Voglio restituire false se l'URL impiega più di 5 secondi per connettersi: come è possibile utilizzando Java? Ecco il codice che sto usando per verificare se l'URL è valido

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

Risposte:


201

HttpURLConnectionha un metodo setConnectTimeout .

Basta impostare il timeout a 5000 millisecondi, quindi catturare java.net.SocketTimeoutException

Il tuo codice dovrebbe assomigliare a questo:


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



3
Ho impostato il valore su 10 minuti. Tuttavia mi lancia un java.net.ConnectException: Connection timed out: connectprima che anche 2 minuti siano trascorsi. Sai cosa sta causando il problema?
Pacerier

5
SocketTimeoutException è una sottoclasse di IOException. Se entrambi i blocchi catch fanno la stessa cosa, potresti semplicemente catturare IOException.
spaaarky21

2
@ spaaarky21 è corretto. Se tuttavia stai creando un'interfaccia utente e desideri informare i tuoi utenti che si è verificato un timeout, devi intercettare SocketTimeoutException prima di IOException, altrimenti non sarà raggiungibile.
Clocker

3
NB !!! è necessario chiamare setConnectTimeoutprima di uno qualsiasi dei metodi che si connettono implicitamente (fondamentalmente tutti i metodi che generano IllegalStateException se già connessi). Idealmente, imposta setConnectTimeout (readTimeout) come primo metodo chiamato.
Adam Gent,

4
Non ha funzionato per me. Ma, dopo aver aggiunto con.setReadTimeout(), ha funzionato come previsto.
Paulo

115

Puoi impostare il timeout in questo modo,

con.setConnectTimeout(connectTimeout);
con.setReadTimeout(socketTimeout);

2
Qual è il valore massimo del timeout che possiamo specificare?
Pacerier

7
@Pacerier I documenti non lo affermano esplicitamente. Genera un'eccezione IllegalArgumentException se il valore è negativo (un valore di 0 significherebbe attendere indefinitamente). Poiché il timeout è un int a 32 bit senza segno, immagino che il timeout massimo sarebbe di circa 49 giorni (anche se dubito seriamente che questo valore possa essere utile a chiunque).
Jay Sidri

1

Se la connessione HTTP non va in timeout, puoi implementare il controllo del timeout nel thread in background stesso (AsyncTask, Service, ecc.), La seguente classe è un esempio per Customize AsyncTask che timeout dopo un certo periodo

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

Un esempio per questo

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

Non è assolutamente necessario creare un nuovo thread looper solo per programmare una chiamata a cancel (). Puoi farlo dal thread principale in onPreExecute(). Inoltre, se annulli l'attività manualmente, dovresti anche annullare la chiamata pianificata per evitare perdite.
BladeCoder

Il punto qui è di annullare AsyncTask nel mezzo di doInBackground () quando impiega troppo tempo all'esecuzione non su onPreExecute (), inoltre voglio annullare solo questa istanza di AsyncTask che richiede troppo tempo e mantiene gli altri, molto apprezzato i tuoi commenti.
Ayman Mahgoub

2
Penso che il mio messaggio non fosse abbastanza chiaro. Non ho detto che dovresti annullare in onPreExecute (), ho detto che dovresti creare il gestore in onPreExecute () e pubblicare l'annullamento ritardato dal thread principale. In questo modo utilizzerai il thread principale come thread looper e puoi ovviamente annullare l'AsyncTask in seguito mentre doInBackground () è in esecuzione perché il thread principale viene eseguito anche contemporaneamente con il thread in background.
BladeCoder

-1

Potrei ottenere una soluzione per un problema simile con l'aggiunta di una semplice riga

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

La mia esigenza era di conoscere il codice di risposta e per questo era sufficiente ottenere le meta-informazioni, invece di ottenere il corpo completo della risposta.

Il metodo di richiesta predefinito è GET e ci è voluto molto tempo per tornare, finalmente mi ha lanciato SocketTimeoutException. La risposta è stata piuttosto rapida quando ho impostato il metodo di richiesta su HEAD.


1
Questa non è in alcun modo la soluzione, stai cambiando il metodo di richiesta in una HEADrichiesta che non produrrà alcun corpo di risposta.
Sveinung Kval Bakken

Questo non aggiunge nulla alla domanda originale. OP ha .setRequestMethod("HEAD")nel loro codice. Stranamente, questa descrizione era esattamente ciò di cui avevo bisogno per ridurre il mio problema di "Troppi file aperti". Quindi grazie?
Joshua Pinter
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.