@Dementor
программист, архитектор, аналитик

Проблема с HttpURLConnection на Android 3.0?

Есть программа написанная для Android. На обычных смартфонах и планшетах никаких проблем нет. Но одни наши клиенты закупили партию дешевых планшетов с версией Android 3.0 на борту и оказалось, что у них нет доступа к ресурсам нашего сайта.

Проверка показала, что наш сервер возвращает ошибку 400 - Bad Request. С помощью ADB я подключился к предоставленному для тестов планшету с записал трафик с помощью tcpdump. Результаты оказались очень любопытными. Сначала на сервер отправляются только заголовки, в которых описывается что это POST-запрос и указываются его параметры. Потом "офигевший" от такого сообщения наш веб-сервер отвечает кодом 400. И только затем отправляется отдельным пакетом содержимое HTTP-пакета (естественно без заголовков, а только тело POSTа).

Судя по тому, что на остальных версиях Android подобной проблемы дробления нет (включая мой эмулятор с Android 2.3), то дело в каких-то нюансах именно третьей версии.

Код довольно простой:

URL oURL = new URL(url);
HttpURLConnection con = (HttpURLConnection) oURL.openConnection();
con.setDoInput(true);
con.setDoOutput(true);
con.setRequestMethod("POST");
con.setRequestProperty("Authorization", auth);
con.setRequestProperty("Content-type" , "text/xml; charset=utf-8");
                
String reqXML = "Тут находится тело POST запроса в кодировке UTF-8";
                
OutputStream reqStream = con.getOutputStream();
reqStream.write(reqXML.getBytes());
reqStream.flush();
                
ByteArrayOutputStream outStream = new ByteArrayOutputStream();
byte[] byteBuf = new byte[1024];
                
int status = con.getResponseCode();
InputStream resStream = null;
if (status >= 400) {
	resStream = con.getErrorStream();
} else {
       	resStream = con.getInputStream();
}
                
int len = resStream.read(byteBuf);
while (len > -1) {
       	outStream.write(byteBuf, 0, len);
       	len = resStream.read(byteBuf);
}

outStream.close();
reqStream.close();
resStream.close();
con.disconnect();

Заранее спасибо за содействие в решении проблемы.

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

byte [] reqBody = reqXML.getBytes();
            	
URL oURL = new URL(pack.url);
HttpURLConnection con = (HttpURLConnection) oURL.openConnection();
                
con.setRequestMethod("POST");
con.setRequestProperty("Authorization", auth);
con.setRequestProperty("SOAPAction"   , action);
con.setRequestProperty("Content-type" , "text/xml; charset=utf-8");
                
con.setDoInput(true);
con.setDoOutput(true);
con.setUseCaches(false);
                
OutputStream reqStream = con.getOutputStream();
reqStream.write(reqBody);
reqStream.close();
........


Но это пока не помогает. Отладка на планшете совместно с запущенным tcpdump на сервере показывает, что на сервер приходит первая часть пакета, получается ответ 400, а потом отсылается остаток сообщения в момент срабатывания инструкции reqStream.close().

Если кому-то интересен вид дампа, то я его добавил комментарием ко второму ответу.
  • Вопрос задан
  • 4662 просмотра
Пригласить эксперта
Ответы на вопрос 2
TonyCode
@TonyCode
С ходу - смутила строка:

reqStream.flush();

Обычно, вместо неё пишу:

reqStream.close();

Есть предположение, что именно из-за flush() отсылается вначале только часть, а когда дойдёт до destroy локального reqStream - он выполняет close() и отсылает POST без заголовков - и это конкретно на 3.0... Советую попробовать заменить строку на close()!
Ответ написан
@antoman
Инженер оптотехник, Разработчик-Сисадмин ABillS
Наткнулся в поисках решения. Может я не последний кто сюда заглянет.
У меня такая проблема выскочила на Android 2.3.3

Оказалось, проблема в setRequestProperty("Authorization", auth), где auth - строка в Base64.

Решилось заменой на Authenticator.
developer.android.com/reference/java/net/Authentic...
Ответ написан
Комментировать
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Похожие вопросы