HttpURLConnection getInputStream: тайм-аут всегда через 180 секунд

Я пытаюсь загрузить файл по очень медленному соединению следующим образом:

    java.net.URL url = new URL("https://X.X.X.X:8443/path/2f6b88cf2b70ee933197edfc9627a9bc/");
    HttpURLConnection connection = (HttpURLConnection)  url.openConnection();
    connection.setRequestMethod("GET");
    connection.setDoOutput(true);
    connection.setConnectTimeout(240 * 1000);
    connection.setReadTimeout(240 * 1000);
    long start = System.currentTimeMillis();
    Files.copy(connection.getInputStream(), new File("test.zip").toPath());
    System.out.println("Time: "+((System.currentTimeMillis() - start) / 1000) + " sec.");

и я заметил, что по некоторым причинам (тайм-аут сокета Windows?) он всегда прерывается после 180 секунд загрузки без каких-либо исключений.

Тайм-аут, установленный в setConnectTimeout(...) или setReadTimeout(...), не помогает.

Я попытался загрузить этот файл с помощью wget:

wget https://X.X.X.X:8443/path/2f6b88cf2b70ee933197edfc9627a9bc/ --no-check-certificate
--2015-09-07 14:36:12--  https://X.X.X.X:8443/path/2f6b88cf2b70ee933197edfc9627a9bc/
Connecting to X.X.X.X:8443... connected.
WARNING: The certificate of ‘X.X.X.X’ is not trusted.
WARNING: The certificate of ‘X.X.X.X’ hasn't got a known issuer.
The certificate's owner does not match hostname ‘X.X.X.X’
HTTP request sent, awaiting response... 302 Found
Location: https://X.X.X.X:8443/files/test.zip [following]
--2015-09-07 14:36:16--  https://X.X.X.X:8443/files/test.zip
Reusing existing connection to X.X.X.X:8443.
HTTP request sent, awaiting response... 200 OK
Length: 321917584 (307M) [application/zip]
Saving to: ‘test.zip’

test.zip                                  100%[====================================================================================>] 307.00M   253KB/s   in 19m 50ss

Полный файл был успешно сохранен на диске через 20 минут.

Что не так с HttpURLConnection?

Изменить: я попытался загрузить тестовый файл с другого сервера по протоколу http, и все было в порядке. Похоже, проблема связана с сервером или протоколом. Но почему wget удается загрузить файл целиком?

Edit2: следуя вашим советам, я также пробовал:

  • удалить соединение.setDoOutput(true);
  • используйте прямую ссылку, чтобы избежать редиректа 302
  • заменить метод Files.copy пользовательской реализацией

К сожалению, ничего из вышеперечисленного не помогает.

Edit3: я заметил, что файл также доступен на том же сервере через незащищенный протокол http. Поэтому я изменил только URL в своем коде и через 120 секунд получил:

Exception in thread "main" java.net.SocketException: Connection reset
    at java.net.SocketInputStream.read(SocketInputStream.java:196)
    at java.net.SocketInputStream.read(SocketInputStream.java:122)
    at java.io.BufferedInputStream.read1(BufferedInputStream.java:273)
    at java.io.BufferedInputStream.read(BufferedInputStream.java:334)
    at sun.net.www.MeteredStream.read(MeteredStream.java:134)
    at java.io.FilterInputStream.read(FilterInputStream.java:133)
    at sun.net.www.protocol.http.HttpURLConnection$HttpInputStream.read(HttpURLConnection.java:3066)
    at sun.net.www.protocol.http.HttpURLConnection$HttpInputStream.read(HttpURLConnection.java:3060)
    at java.nio.file.Files.copy(Files.java:2735)
    at java.nio.file.Files.copy(Files.java:2854) 

person Tomasz Ceszke    schedule 08.09.2015    source источник
comment
Мое понимание readTimeout заключается в том, что количество времени ожидания до доступности данных. Во всяком случае, они в миллисекундах, а вы дали 240 000 - 4 минуты.   -  person Dakshinamurthy Karra    schedule 08.09.2015
comment
Я попытался уменьшить оба таймаута до 10 секунд или увеличить до 10 минут, но он всегда прерывается после 180 секунд.   -  person Tomasz Ceszke    schedule 08.09.2015
comment
Не могли бы вы опубликовать полную трассировку стека наблюдаемого исключения?   -  person Little Santi    schedule 08.09.2015
comment
@LittleSanti Я должен упомянуть, что исключений нет. Программа завершается нормально.   -  person Tomasz Ceszke    schedule 08.09.2015
comment
@tomek.ceszke Из вывода wget видно, что есть перенаправление 302. Вместо использования текущего URL-адреса вы можете попробовать перенаправленный URL-адрес и посмотреть, что произойдет?   -  person Dakshinamurthy Karra    schedule 08.09.2015
comment
@KDM Только что проверил, не помогло. HttpURLConnections правильно следует перенаправлениям.   -  person Tomasz Ceszke    schedule 08.09.2015
comment
@tomek.ceszke Если явной ошибки нет, каково возможное содержимое файла test.zip?   -  person Little Santi    schedule 08.09.2015
comment
@tomek.ceszke Является ли этот код частью более крупной программы или отдельной? Files.copy возвращает количество скопированных байтов. Можете ли вы напечатать это значение?   -  person Dakshinamurthy Karra    schedule 08.09.2015
comment
@KDM Copied 209747968 bytes in 180 sec Исходный размер 307 МБ   -  person Tomasz Ceszke    schedule 08.09.2015


Ответы (2)


Наконец-то я нашел решение здесь Это невозможно для загрузки больших файлов на сервер Jetty (еще раз спасибо StackOverflow). Проблема была на стороне сервера.

Jetty 9.2, который мы использовали, имеет ошибку, которая прерывает обслуживание больших файлов при медленном соединении (https://bugs.eclipse.org/bugs/show_bug.cgi?id=472621). Кажется, что исключение не всегда выбрасывается.

Wget и браузеры каким-то образом смогли завершить загрузку, несмотря на остановку передачи или сброс соединения. К сожалению, мое Java-приложение было более чувствительным...

Обновление комплектного Jetty до последней стабильной версии 9.3.3 исправило все проблемы с загрузками.

person Tomasz Ceszke    schedule 11.09.2015

connection.setRequestMethod("GET");

Здесь вы собираетесь выполнить HTTP GET.

connection.setDoOutput(true);

Здесь вы меняете его на PUT.

Files.copy(connection.getInputStream(), new File("test.zip").toPath());

Здесь вы получаете входной поток, даже ничего не написав. Сервер все еще ожидает данные POST, которые вы никогда не отправляете, поэтому он никогда не отправляет ответ, поэтому вы истекаете.

Потерять строку setDoOutput(true);.

person user207421    schedule 08.09.2015
comment
Спасибо за ответ, но это не помогло. - person Tomasz Ceszke; 08.09.2015
comment
Вам придется показать, что вы сделали. Отредактируйте его в своем вопросе. - person user207421; 08.09.2015