webentwicklung-frage-antwort-db.com.de

Sichere Verwendung von HttpURLConnection

Muss bei der Verwendung von HttpURLConnection der InputStream geschlossen werden, wenn wir ihn nicht 'bekommen' und verwenden?

ist das sicher?

HttpURLConnection conn = (HttpURLConnection) uri.getURI().toURL().openConnection();
conn.connect();
// check for content type I don't care about
if (conn.getContentType.equals("image/gif") return; 
// get stream and read from it
InputStream is = conn.getInputStream();
try {
    // read from is
} finally {
    is.close();
}

Ist es zweitens sicher, einen InputStream zu schließen, bevor sein gesamter Inhalt vollständig gelesen wurde ?

Besteht die Gefahr, dass der zugrunde liegende Socket im Zustand ESTABLISHED oder sogar CLOSE_WAIT belassen wird?

47
Joel

ist es sicher, einen InputStream zu schließen, bevor sein gesamter Inhalt gelesen wurde?

Sie müssen alle Daten im Eingabestream lesen, bevor Sie ihn schließen, damit die zugrunde liegende TCP) - Verbindung zwischengespeichert wird. Ich habe gelesen, dass sie im neuesten Java nicht erforderlich sein sollte, aber es war Immer beauftragt, die gesamte Antwort für die Wiederverwendung der Verbindung zu lesen.

Überprüfen Sie diesen Beitrag: Keep-Alive in Java6

28
Cratylus

Laut http://docs.Oracle.com/javase/6/docs/technotes/guides/net/http-keepalive.html und OpenJDK-Quellcode.

(Wenn keepAlive == true)

Wenn der Client HttpURLConnection.getInputSteam().close() aufgerufen hat, wird der spätere Aufruf von HttpURLConnection.disconnect() NICHT schließenSocket. d.h. das Socket wird wiederverwendet (zwischengespeichert)

Wenn der Client close() nicht aufruft, wird durch Aufrufen von disconnect() das InputStream und das Socket geschlossen.

Um das Socket wiederzuverwenden, rufen Sie einfach InputStream.close() auf. Rufen Sie HttpURLConnection.disconnect() nicht auf.

34
Anderson Mao

Hier finden Sie einige Informationen zum Keep-Alive-Cache. Alle diese Informationen beziehen sich auf Java 6, sind aber wahrscheinlich auch für viele frühere und spätere Versionen zutreffend.

Soweit ich das beurteilen kann, läuft der Code auf Folgendes hinaus:

  1. Wenn der Remote-Server einen "Keep-Alive" -Header mit einem "Timeout" -Wert sendet, der als positive Ganzzahl analysiert werden kann, wird diese Anzahl von Sekunden für das Timeout verwendet.
  2. Wenn der Remote-Server einen "Keep-Alive" -Header sendet, aber keinen "Timeout" -Wert hat, der als positive Ganzzahl und analysiert werden kann "usingProxy" ist wahr, dann beträgt das Timeout 60 Sekunden.
  3. In allen anderen Fällen beträgt die Zeitüberschreitung 5 Sekunden.

Diese Logik ist auf zwei Stellen aufgeteilt: um die Zeile 725 von Sun.net.www.http.HttpClient (in der Methode "parseHTTPHeader") und um die Zeile 120 von Sun.net. www.http.KeepAliveCache (in der "put" -Methode).


Es gibt also zwei Möglichkeiten, den Timeout-Zeitraum zu steuern:

  1. Steuern Sie den Remote-Server und konfigurieren Sie ihn so, dass ein Keep-Alive-Header mit dem richtigen Zeitlimitfeld gesendet wird
  2. Ändern Sie den JDK-Quellcode und erstellen Sie Ihren eigenen.

Man könnte meinen, dass es möglich wäre, den scheinbar willkürlichen Fünf-Sekunden-Standard zu ändern, ohne interne JDK-Klassen neu zu kompilieren, aber das ist es nicht. Ein Bug wurde 2005 eingereicht, um diese Fähigkeit anzufordern, aber Sun weigerte sich, sie bereitzustellen.

18

Wenn Sie wirklich sicherstellen möchten, dass die Verbindung geschlossen ist, sollten Sie conn.disconnect() aufrufen.

Die von Ihnen beobachteten offenen Verbindungen sind auf die Funktion zum Aufrechterhalten der HTTP 1.1-Verbindung zurückzuführen (auch bekannt als HTTP Persistent Connections ). Wenn der Server HTTP 1.1 unterstützt und kein Connection: close Im Antwortheader sendet, wird Java die zugrunde liegende TCP Verbindung nicht sofort geschlossen, wenn Sie den Eingabestream schließen. Stattdessen wird es geöffnet und versucht, es für die nächste HTTP-Anforderung an denselben Server erneut zu verwenden.

Wenn Sie dieses Verhalten überhaupt nicht möchten, können Sie die Systemeigenschaft http.keepAlive Auf false setzen:

System.setProperty("http.keepAlive","false");
7
Robert

Sie müssen den Fehlerstrom auch schließen, wenn die HTTP-Anforderung fehlschlägt (alles andere als 200):

try {
  ...
}
catch (IOException e) {
  connection.getErrorStream().close();
}

Wenn Sie dies nicht tun, verlieren alle Anforderungen, die nicht 200 zurückgeben (z. B. Zeitüberschreitung), einen Socket.

3
Vlad Lifliand

Muss bei der Verwendung von HttpURLConnection der InputStream geschlossen werden, wenn wir ihn nicht 'bekommen' und verwenden?

Ja, es muss immer geschlossen sein.

ist das sicher?

Nicht 100%, Sie laufen Gefahr, eine NPE zu bekommen. Sicherer ist:

InputStream is = null;
try {
    is = conn.getInputStream()
    // read from is
} finally {
    if (is != null) {
        is.close();
    }
}
1
Arjan Tijms