Android (Java) HttpURLConnection отключить повторную попытку в режиме ожидания чтения

Поэтому я использую Google Volley для HTTP-запроса, который в основном использует Java HttpURLConnection.

Согласно моим тестам, проблема заключается в этом:
Когда время ожидания "чтения" на HttpURLConnection достигает, перед закрытием соединения выполняется молчащий повтор, а соответствующее исключение выбрано (SocketTimeoutException).

Примечание, что:
- Я заметил эту ошибку при использовании запроса HTTP POST.
- Тайм-аут "чтения" отличается от тайм-аута "connect".
- Если тайм-аут "read" (установленный вызовом connection.setReadTimeout(int)) НЕ установлен (0) или установлен на большее значение, чем connection.setConnectTimeout(int), эта ошибка не возникает.
- Этот вопрос обсуждался, например, здесь, но я не нашел удовлетворительного решения.
- Несколько сопутствующую проблему можно найти здесь, но я не уверен, что это релевантно (не так ли?)

Дополнительные сведения
Мое приложение используется для оплаты денег, поэтому не требуется повторная попытка запроса (да, я знаю, что он может обрабатываться сервером, я хочу, чтобы мой клиент был "правильным" ) в любом случае).

Когда установлен тайм-аут "read" , в случае установления соединения с сервером, но сервер ожидает /sleeps/delayays -response, время "timeout" перед ответом (таким образом, возникает исключение "read" , а не "connect" ') другой (тихий) запрос отправляется непосредственно перед тем, как это исключение будет поднято, в результате чего будут получены 2 похожих запроса, что неприемлемо.

Какое решение я ищу?
Ну, это тот, который будет хорошо решить эту проблему/ошибку, так же, как исправлено объяснение здесь (но я снова считаю, что это не имеет значения в этом случай).
Кроме того, я хотел бы сохранить исходный поток как есть, что означает не принуждение соединения к закрытию или что-то в этом роде.

То, что я собираюсь сделать на данный момент, устанавливает тайм-аут "read" в два раза "тайм-аут соединения" (они начинают подсчитывать в то же время), чтобы убедиться, что исключение "connection" возникает в первую очередь. Я также попытаюсь решить эту проблему на стороне сервера. Проблема в том, что этот тайм-аут "read" существует по какой-то причине, и моя текущая реализация практически просто игнорирует его и обрабатывает только таймауты "соединения".

ИЗМЕНИТЬ Библиотека Volley RetryPolicy не повлияла на эту проблему, так как это повторение молчания. Я выглядел как можно глубже в библиотеке. Журналы/точки останова повсюду, отменены вызовы повторной попытки. Это, как я знаю, это проблема 99.99% a HttpURLConnection.

Ответы

Ответ 1

Это плохое решение было принято разработчиком в 2006 году. Вот хорошая цитата от кого-то, которая объясняет всю ситуацию с точки зрения java:

"Как вы, наверное, догадались, что теперь это ошибка ( http://bugs.java.com/bugdatabase/view_bug.do?bug_id=6382788). Не механизм повтора, конечно, просто дерьмо Ошибка в том, что это также происходит для POST (который по умолчанию не является идемпотентным для HTTP RFC). Но не беспокойтесь, Билл давно исправил эту ошибку. Билл исправил ее, введя переключатель. Билл узнал о отсталых Билл решил, что лучше оставить переключатель 'on' по умолчанию, потому что это сделает его совместимым с ошибкой. Билл улыбается. Он уже может видеть лица удивленных разработчиков по всему миру. как Билл?" Источник

Ну, предлагаемое решение:

System.setProperty("sun.net.http.retryPost", "false")

Но мы не можем сделать это на android! Единственным оставшимся решением будет следующее:

httpURLConnection.setChunkedStreamingMode(0);

Который, кажется, работает, но не очень эффективен с точки зрения запроса времени.

EDIT: Я не мог использовать эту реализацию, поэтому я искал альтернативную библиотеку. Я узнал, что реализация HttpUrlConnection использует OkHttp с Android 4.4. Поскольку OkHttp - это open source, я мог бы искать, есть ли у них проблемы с молчаливыми попытками. И у них были проблемы с ним и исправлено в апреле 2016 года. CommonsWare (настоящий специалист по Android) объясняет, что каждый производитель может решить, какую реализацию они могут использовать. Вследствие этого должно быть много устройств, которые делают молчание в ответах на POST-запросы, и в качестве разработчика мы можем попробовать только некоторые варианты работы.

Моим решением будет изменение библиотеки

EDIT 2: Чтобы дать вам окончательный ответ: Теперь вы можете использовать OkHttp как транспортный уровень для Volley с минимальным кодом.

Еще одно полезное решение

Ответ 2

Ну, прошло много времени, поэтому я решил, что отвечу моим текущим (не идеальным) решением для других людей, чтобы его легко увидеть (также написано внутри вопроса).

Просто установите readTimeout равным 0 (без тайм-аута) или, по крайней мере, значением таймаута соединения. Это позволит убедиться, что таймаут соединения будет поднят до таймаута чтения.

int timeoutMs = request.getTimeoutMs();    //  or whatever
connection.setConnectTimeout(timeoutMs);   //  actual timeout desired
connection.setReadTimeout(timeoutMs);      //  >= timeoutMs or 0

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

Как сказано, на самом деле это не "решение", а очень приятное и полезное решение на 90%.

Ответ 3

Вы можете проверить класс DefaultRetryPolicy волейбола.