Uso sicuro di HttpURLConnection

Quando si usa HttpURLConnection, l’InputStream deve essere chiuso se non lo si “usa” e lo si usa?

cioè è sicuro?

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

In secondo luogo, è sicuro chiudere un InputStream prima che tutto il suo contenuto sia stato letto completamente ?

C’è il rischio di lasciare il socket sottostante in stato ESTABLISHED o anche CLOSE_WAIT?

è sicuro chiudere un InputStream prima che tutti i suoi contenuti siano stati letti

È necessario leggere tutti i dati nel stream di input prima di chiuderlo in modo che la connessione TCP sottostante venga memorizzata nella cache. Ho letto che non dovrebbe essere richiesto nell’ultima versione di Java, ma è sempre stato richiesto di leggere l’intera risposta per il riutilizzo della connessione.

Controlla questo post: keep-alive in java6

Secondo http://docs.oracle.com/javase/6/docs/technotes/guides/net/http-keepalive.html e codice sorgente OpenJDK.

(Quando keepAlive == true)

Se il client ha chiamato HttpURLConnection.getInputSteam (). close (), la successiva chiamata a HttpURLConnection. disconnect () NON chiude la presa. cioè The Socket viene riutilizzato (memorizzato nella cache)

Se il client non chiama close (), call disconnect () chiuderà InputSteam e chiuderà il socket.

Quindi, per riutilizzare Socket, basta chiamare InputStream close (). Non chiamare HttpURLConnection disconnect ().

Ecco alcune informazioni riguardanti la cache keep-alive. Tutte queste informazioni riguardano Java 6, ma probabilmente sono anche accurate per molte versioni precedenti e successive.

Da quello che posso dire, il codice si riduce a:

  1. Se il server remoto invia un’intestazione “Keep-Alive” con un valore “timeout” che può essere analizzato come un numero intero positivo, viene utilizzato quel numero di secondi per il timeout.
  2. Se il server remoto invia un’intestazione “Keep-Alive” ma non ha un valore di “timeout” che può essere analizzato come numero intero positivo e “usingProxy” è true, il timeout è 60 secondi.
  3. In tutti gli altri casi, il timeout è 5 secondi.

Questa logica è suddivisa in due parti: attorno alla linea 725 di sun.net.www.http.HttpClient (nel metodo “parseHTTPHeader”), e attorno alla riga 120 di sun.net.www.http.KeepAliveCache (nel “put” metodo).


Quindi, ci sono due modi per controllare il periodo di timeout:

  1. Controlla il server remoto e configuralo per inviare un’intestazione Keep-Alive con il campo timeout appropriato
  2. Modifica il codice sorgente JDK e creane uno tuo.

Si potrebbe pensare che sarebbe ansible cambiare il default apparentemente arbitrario di cinque secondi senza ricompilare le classi JDK interne, ma non lo è. Nel 2005 è stato presentato un bug per richiedere questa abilità, ma Sun si è rifiutato di fornirlo.

Se vuoi veramente assicurarti che la connessione sia vicina, devi chiamare conn.disconnect() .

Le connessioni aperte che hai osservato sono dovute alla funzionalità keep alive di HTTP 1.1 (anche conosciuta come HTTP Persistent Connections ). Se il server supporta HTTP 1.1 e non invia una Connection: close nell’intestazione della risposta Java non chiude immediatamente la connessione TCP sottostante quando si chiude il stream di input. Invece lo tiene aperto e tenta di riutilizzarlo per la successiva richiesta HTTP allo stesso server.

Se non si desidera affatto questo comportamento, è ansible impostare la proprietà di sistema http.keepAlive su false:

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

Devi anche chiudere il stream di errori se la richiesta HTTP fallisce (tranne che 200):

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

Se non lo fai, tutte le richieste che non restituiscono 200 (ad es. Timeout) perdono un socket. Vedi http://scotte.github.io/2015/01/httpurlconnection-socket-leak/ per maggiori dettagli.

Quando si usa HttpURLConnection, l’InputStream deve essere chiuso se non lo si “usa” e lo si usa?

Sì, deve sempre essere chiuso.

cioè è sicuro?

Non al 100%, corri il rischio di ottenere un NPE. Più sicuro è:

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