Безопасное использование HttpURLConnection - PullRequest
46 голосов
/ 22 января 2011

При использовании HttpURLConnection необходимо ли закрыть InputStream, если мы не «получаем» и не используем его?

т.е. это безопасно?

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

Во-вторых, безопасно ли закрыть InputStream до того, как все его содержимое будет полностью прочитано ?

Есть ли риск оставить базовый сокет в состоянии ESTABLISHED или даже в состоянии CLOSE_WAIT?

Ответы [ 6 ]

33 голосов
/ 18 июля 2012

Согласно http://docs.oracle.com/javase/6/docs/technotes/guides/net/http-keepalive.html и исходный код OpenJDK.

(Когда keepAlive == true)

Если клиент вызвал HttpURLConnection.getInputSteam().<strong>close</strong>(), более поздний вызов HttpURLConnection.<strong>disconnect</strong>() будет НЕ закрывать Socket. то есть Socket используется повторно (кэшируется)

Если клиент не вызывает close(), вызов disconnect() закроет InputStream и закроет Socket.

Итак, чтобы повторно использовать Socket, просто позвоните InputStream.<strong>close</strong>(). Не звоните HttpURLConnection.<strong>disconnect</strong>().

28 голосов
/ 22 января 2011

безопасно ли закрыть InputStream прежде чем весь его контент был читать

Вам необходимо прочитать все данные во входном потоке, прежде чем закрыть его, чтобы базовое TCP-соединение кэшировалось. Я прочитал, что это не должно требоваться в последней Java, но всегда требовалось прочитать весь ответ для повторного использования соединения.

Проверьте это сообщение: keep-alive в java6

18 голосов
/ 28 сентября 2011

Вот некоторая информация о кеше keep-alive.Вся эта информация относится к Java 6, но, вероятно, также точна для многих предыдущих и более поздних версий.

Из того, что я могу сказать, код сводится к:

  1. Если удаленныйсервер отправляет заголовок «Keep-Alive» со значением «timeout», которое может быть проанализировано как положительное целое число, это количество секунд используется для timeout.
  2. Если удаленный сервер отправляет «Keep-Alive»"header, но у него нет значения" timeout ", которое может быть проанализировано как положительное целое число и " usingProxy "равно true, тогда время ожидания равно 60 секундам.
  3. Во всех остальныхВ некоторых случаях время ожидания составляет 5 секунд.

Эта логика разделена между двумя местами: вокруг строки 725 из sun.net.www.http.HttpClient (в "parseHTTPHeader"метод), и вокруг строки 120 sun.net.www.http.KeepAliveCache (в методе "put").


Итак, есть два способа управлениявремя ожидания:

  1. Управление удаленным сервером и настройка его отправкиKeep-Alive header с правильным полем тайм-аута
  2. Измените исходный код JDK и создайте свой собственный.

Можно подумать, что можно было бы изменить явно произвольную пятисекунднуюпо умолчанию без перекомпиляции внутренних классов JDK, но это не так. ошибка была подана в 2005 году с просьбой предоставить эту возможность, но Sun отказалась предоставить ее.

7 голосов
/ 22 января 2011

Если вы действительно хотите убедиться, что соединение установлено, вы должны позвонить conn.disconnect().

Открытые соединения, которые вы наблюдали из-за функции поддержания соединения HTTP 1.1, также известной как Постоянные соединения HTTP ).Если сервер поддерживает HTTP 1.1 и не отправляет Connection: close в заголовке ответа, Java не сразу закрывает нижележащее TCP-соединение при закрытии входного потока.Вместо этого он сохраняет его открытым и пытается повторно использовать его для следующего HTTP-запроса к тому же серверу.

Если вам вообще не нужно это поведение, вы можете установить для системного свойства http.keepAlive значение false:

System.setProperty("http.keepAlive","false");
3 голосов
/ 06 января 2016

Вы также должны закрыть поток ошибок в случае сбоя HTTP-запроса (что угодно, кроме 200):

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

Если вы этого не сделаете, все запросы, которые не возвращают 200 (например, время ожидания)протечет одна розетка.

1 голос
/ 22 января 2011

При использовании HttpURLConnection необходимо ли закрыть InputStream, если мы не «получаем» и не используем его?

Да, его всегда нужно закрывать.

т.е. это безопасно?

Не 100%, вы рискуете получить NPE. Более безопасным является:

InputStream is = null;
try {
    is = conn.getInputStream()
    // read from is
} finally {
    if (is != null) {
        is.close();
    }
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...