Apache HttpClient 4.x ведет себя странно при загрузке больших файлов? - PullRequest
4 голосов
/ 06 февраля 2012

Я занимаюсь разработкой и тестированием небольшого простого клиент-серверного приложения с использованием Java (и Scala).

Сервер основан на com.sun.net.httpserver.HttpServer и позволяет загружать файлы через базовый интерфейс RESTful с использованием операций POST и PUT.Операция загрузки ограничена с помощью дайджест-аутентификации , которую мы реализовали сами, протестирована и работает в браузерах, curl и Apache HttpClient.

клиент загрузки оболочек Apache HttpClient 4.1.2 и выполняет операции PUT через http для загрузки файловых сущностей.Тип содержимого файла указан как application/xml в заголовке, и за один раз загружается только один файл.

При загрузке файлов разных размеров странное поведение может бытьнаблюдается:

  • Файлы с размерами меньше или равными 1.076.006 байт загружены успешно .
  • Файлы с размерами больше или равны 1.122.158 байт сбой с java.net.SocketException: Broken pipe.

( Точный критический размер неизвестен, поскольку я вручную создал файлы с различными размерами, чтобы приблизить максимальный рабочий размер )

Причина разбитого канала в том, что клиент каким-то образом игнорировал www-authenticate -ответ загрузки файлов такого размера, что задокументировано журналами сервера.«Игнорировать» означает, что он просто отправляет несколько (4) сообщений, не содержащих вообще никакого заголовка аутентификации.Но файлы меньшего размера работают хорошо, и клиент отправляет запрос аутентификации с правильным ответом-запросом правильно сразу после ответа www-authenticate, как и должно быть.

Загрузка работаетв curl с файлами всех размеров, так что никаких проблем нет.

Итак, на этом этапе можно сказать: «В вашем клиенте есть какая-то ошибка».Хорошо, я вроде бы на это надеюсь, но Я также попробовал java RESTclient с открытым исходным кодом (также упаковывающий apache httpclient), и он имеет точно то же самоеповедение!

Мы попробовали его с помощью этого клиента через Интернет, а также так же, как описано.Итак, прямо сейчас, я просто надеюсь, что упустил установить что-то важное в Apache HttpClient, что приводит к этому ошибочному поведению, и разработчик RESTclient с открытым исходным кодом также упустил это ... любые идеи, что бы это могло быть, были бы хорошими!

1 Ответ

6 голосов
/ 07 февраля 2012

Скорее всего, это сочетание нескольких факторов, которые приводят к этой ситуации

(1) Скорее всего, ваш клиент не использует рукопожатие «ожидаем-продолжаем» при отправке объекта большого запроса с запросом, который делаетне включает заголовок аутентификации.

(2) Сервер рано обнаруживает, что запрос не соответствует ожиданиям, и вместо чтения и отбрасывания полного тела запроса он отвечает рано с состоянием 401 и закрывает соединение на своем конце.На мой взгляд, это нарушение протокола HTTP со стороны сервера.

(3) Хотя некоторые HTTP-агенты могут иметь дело с ранними ответами, Apache HttpClient не может из-за ограничения блокировки ввода-вывода Java(поток выполнения может либо читать, либо записывать из блокирующего сокета, но не оба).

Существует несколько способов решения проблемы, рукопожатие «ожидай-продолжай» является самым простым и наиболее естественным.В качестве альтернативы можно выполнить простой запрос HEAD или GET для принудительной аутентификации HTTP перед выполнением большого запроса POST или PUT.HttpClient может повторно использовать данные аутентификации для последующих запросов в том же логическом сеансе HTTP.

...