Подтвердить что ты не робот

Безопасное использование HttpURLConnection

При использовании 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?

4b9b3361

Ответ 1

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

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

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

Ответ 2

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

(Когда keepAlive == true)

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

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

Таким образом, чтобы повторно использовать Socket, просто вызовите InputStream. close() InputStream. close(). Не звоните HttpURLConnection. disconnect() HttpURLConnection. disconnect().

Ответ 3

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

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

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

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


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

  • Управляйте удаленным сервером и настраивайте его для отправки заголовка Keep-Alive с соответствующим полем тайм-аута
  • Измените исходный код JDK и создайте свой собственный.

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

Ответ 4

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

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

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

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

Ответ 5

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

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

Если вы этого не сделаете, все запросы, которые не возвращают 200 (например, тайм-аут), будут пропускать один сокет.

Ответ 6

При использовании HttpURLConnection нужно ли закрывать InputStream, если мы не "получаем" и не используем его?

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

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

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

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