Einstellungen für das Zeitlimit für HttpURLConnection

123

Ich möchte false zurückgeben, wenn die Verbindung der URL länger als 5 Sekunden dauert. Wie ist dies mit Java möglich? Hier ist der Code, mit dem ich überprüfe, ob die URL gültig ist

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

Antworten:

201

HttpURLConnectionhat eine setConnectTimeout- Methode.

Stellen Sie das Timeout einfach auf 5000 Millisekunden ein und fangen Sie dann ab java.net.SocketTimeoutException

Ihr Code sollte ungefähr so ​​aussehen:


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
quelle
3
Ich habe den Wert auf 10 Minuten eingestellt. Allerdings wirft es mich java.net.ConnectException: Connection timed out: connectvor noch 2 Minuten auf. Wissen Sie, was das Problem verursacht?
Pacerier
5
SocketTimeoutException ist eine Unterklasse von IOException. Wenn beide Catch-Blöcke dasselbe tun, können Sie einfach IOException abfangen.
spaaarky21
2
@ spaaarky21 ist korrekt. Wenn Sie jedoch eine Benutzeroberfläche erstellen und Ihre Benutzer über ein Zeitlimit informieren möchten, müssen Sie SocketTimeoutException vor IOException abfangen. Andernfalls ist es nicht erreichbar.
Clocker
3
NB !!! Sie müssen setConnectTimeoutvor jeder der Methoden aufrufen , die implizit eine Verbindung herstellen (im Grunde alle Methoden, die IllegalStateException auslösen, wenn sie bereits verbunden sind). Machen Sie im Idealfall setConnectTimeout (readTimeout) zu den ersten aufgerufenen Methoden.
Adam Gent
4
Bei mir hat es nicht funktioniert. Aber nach dem Hinzufügen con.setReadTimeout()funktionierte es wie erwartet.
Paulo
115

Sie können das Zeitlimit wie folgt einstellen:

con.setConnectTimeout(connectTimeout);
con.setReadTimeout(socketTimeout);
ZZ Coder
quelle
2
Was ist der maximale Wert des Zeitlimits, das wir angeben können?
Pacerier
7
@Pacerier In den Dokumenten wird dies nicht explizit angegeben. Es wird eine IllegalArgumentException ausgelöst, wenn der Wert negativ ist (ein Wert von 0 würde bedeuten, auf unbestimmte Zeit zu warten). Da es sich bei dem Timeout um ein vorzeichenloses 32-Bit-Int handelt, würde ich davon ausgehen, dass das maximale Timeout etwa 49 Tage beträgt (obwohl ich ernsthaft bezweifle, dass ein solcher Wert für jeden hilfreich wäre).
Jay Sidri
1

Wenn für die HTTP-Verbindung keine Zeitüberschreitung auftritt, können Sie die Zeitüberschreitungsprüfung im Hintergrundthread selbst (AsyncTask, Service usw.) implementieren. Die folgende Klasse ist ein Beispiel für das Anpassen von AsyncTask, bei dem nach einer bestimmten Zeit eine Zeitüberschreitung auftritt

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

Ein Beispiel dafür

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
quelle
Es ist absolut unnötig, einen neuen Looper-Thread zu erstellen, um einen Aufruf zum Abbrechen () zu planen. Sie können dies vom Haupt-Thread in tun onPreExecute(). Wenn Sie die Aufgabe manuell abbrechen, sollten Sie auch den geplanten Anruf abbrechen, um Undichtigkeiten zu vermeiden.
BladeCoder
Hier geht es darum, AsyncTask in der Mitte von doInBackground () abzubrechen, wenn es bei der Ausführung zu lange dauert, nicht bei onPreExecute (). Außerdem möchte ich nur diese Instanz von AsyncTask abbrechen, die zu viel Zeit in Anspruch nimmt und die anderen sehr schätzen Ihre Rückmeldung.
Ayman Mahgoub
2
Ich denke, meine Botschaft war nicht klar genug. Ich habe nicht gesagt, dass Sie in onPreExecute () abbrechen sollen, ich habe gesagt, Sie sollten den Handler in onPreExecute () erstellen und den verzögerten Abbruch aus dem Hauptthread veröffentlichen. Auf diese Weise verwenden Sie den Hauptthread als Looper-Thread und können die AsyncTask natürlich später abbrechen, während doInBackground () ausgeführt wird, da der Hauptthread auch gleichzeitig mit dem Hintergrundthread ausgeführt wird.
BladeCoder
-1

Ich könnte eine Lösung für solch ein ähnliches Problem durch Hinzufügen einer einfachen Zeile erhalten

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

Meine Anforderung bestand darin, den Antwortcode zu kennen, und dafür war es ausreichend, nur die Metainformationen zu erhalten, anstatt den vollständigen Antworttext zu erhalten.

Die Standardanforderungsmethode ist GET. Die Rückkehr hat viel Zeit in Anspruch genommen und mir schließlich die SocketTimeoutException ausgelöst. Die Antwort war ziemlich schnell, als ich die Anforderungsmethode auf HEAD setzte.

Subrata Nath
quelle
1
Dies ist in keiner Weise die Lösung. Sie ändern die Anforderungsmethode in eine HEADAnforderung, die keinen Antworttext erzeugt.
Sveinung Kval Bakken
Dies fügt der ursprünglichen Frage nichts hinzu. OP hat .setRequestMethod("HEAD")in ihrem Code. Seltsamerweise war diese Beschreibung genau das, was ich brauchte, um mein Problem mit "Zu viele geöffnete Dateien" zu reduzieren. So danke?
Joshua Pinter