Android: HttpURLConnection не работает должным образом

Я пытаюсь получить файлы cookie с веб-сайта после отправки учетных данных пользователя через запрос POST, и кажется, что он не работает в Android таким образом. ¿Я делаю что-то плохое?. Пожалуйста помоги. Я искал здесь в разных сообщениях, но полезного ответа нет.

Любопытно, что этот запуск в настольной реализации Java работает отлично, но сбой на платформе Android. И это точно такой же код, особенно при вызове HttpURLConnection.getHeaderFields(), это также происходит с другими методами-членами. Это простой код, и я не знаю, почему, черт возьми, он не работает.

КОД DESKTOP: это происходит только в main()

HttpURLConnection connection = null;
        OutputStream out = null;
        try {                   
            URL url = new URL("http://www.XXXXXXXX.php");           
            String charset = "UTF-8";       

            String postback = "1";
            String user = "XXXXXXXXX";
            String password = "XXXXXXXX";
            String rememberme = "on";
            String query = String.format("postback=%s&user=%s&password=%s&rememberme=%s"
                    , URLEncoder.encode(postback, charset)
                    , URLEncoder.encode(user,charset)
                    , URLEncoder.encode(password, charset)
                    , URLEncoder.encode(rememberme, charset));

            connection = (HttpURLConnection)url.openConnection();
            connection.setRequestMethod("POST");
            connection.setRequestProperty("Accept-Charset", charset);
            connection.setDoOutput(true);           
            connection.setFixedLengthStreamingMode(query.length());

            out = connection.getOutputStream ();
            out.write(query.getBytes(charset));

            if (connection.getHeaderFields() == null){
                System.out.println("Header null");
            }else{
                for (String cookie: connection.getHeaderFields().get("Set-Cookie")){
                    System.out.println(cookie.split(";", 2)[0]);
                }
            }
        } catch (IOException e){
            e.printStackTrace();
        } finally {
            try { out.close();} catch (IOException e) { e.printStackTrace();}
            connection.disconnect();            
        }

Итак, вывод:

    login_key=20ad8177db4eca3f057c14a64bafc2c9
    FASID=cabf20cc471fcacacdc7dc7e83768880
    track=30c8183e4ebbe8b3a57b583166326c77
    client-data=%7B%22ism%22%3Afalse%2C%22showm%22%3Afalse%2C%22ts%22%3A1349189669%7D

КОД ANDROID: находится внутри тела doInBackground AsyncTask

HttpURLConnection connection = null;
            OutputStream out = null;
            try {                   
                URL url = new URL("http://www.XXXXXXXXXXXXXX.php");         
                String charset = "UTF-8";       

                String postback = "1";
                String user = "XXXXXXXXX";
                String password = "XXXXXXXX";
                String rememberme = "on";
                String query = String.format("postback=%s&user=%s&password=%s&rememberme=%s"
                        , URLEncoder.encode(postback, charset)
                        , URLEncoder.encode(user,charset)
                        , URLEncoder.encode(password, charset)
                        , URLEncoder.encode(rememberme, charset));

                connection = (HttpURLConnection)url.openConnection();
                connection.setRequestMethod("POST");
                connection.setRequestProperty("Accept-Charset", charset);
                connection.setDoOutput(true);           
                connection.setFixedLengthStreamingMode(query.length());

                out = connection.getOutputStream ();
                out.write(query.getBytes(charset));

                if (connection.getHeaderFields() == null){
                    Log.v(TAG, "Header null");
                }else{
                    for (String cookie: connection.getHeaderFields().get("Set-Cookie")){
                        Log.v(TAG, cookie.split(";", 2)[0]);
                    }
                }
            } catch (IOException e){
                e.printStackTrace();
            } finally {
                try { out.close();} catch (IOException e) { e.printStackTrace();}
                connection.disconnect();            
            }

А здесь нет вывода, похоже, что connection.getHeaderFields() не возвращает результат. Для отображения журнала требуется не менее 30 секунд:

10-02 16:56:25.918: V/class com.giorgi.myproject.activities.HomeActivity(2596): Header null

ПРОВЕРЕНО НА GALAXY NEXUS


person giorgiline    schedule 02.10.2012    source источник
comment
вам может понадобиться сбросить или закрыть выходной поток?   -  person njzk2    schedule 02.10.2012
comment
Он закрыт в предложении finally. Я также пробовал флеш, как вы сказали, но ничего не происходит.   -  person giorgiline    schedule 02.10.2012
comment
я имел в виду до прочтения заголовков   -  person njzk2    schedule 02.10.2012
comment
вы получаете запрос на сервер?   -  person njzk2    schedule 02.10.2012
comment
Как мне это проверить? Выполняя connection.getResponseMessage(), он выдает: 10-02 17:56:44.332: W/System.err(5177): java.io.EOFException   -  person giorgiline    schedule 02.10.2012
comment
у тебя есть рука на сервере?   -  person njzk2    schedule 02.10.2012
comment
Я согласен, что getHeaderFields() иногда возвращает значение null. Мы не могли понять, в каких случаях.   -  person Snicolas    schedule 14.08.2013


Ответы (4)


Я понял, в чем была проблема. Похоже, что при использовании Java Desktop флаг FollowRedirects по умолчанию установлен как false (я полагаю), а в Android — это правда. getInstanceFollowRedirects имеет значение TRUE в обоих случаях, поэтому я действительно не знаю, почему это работает по-другому, но неважно, решение идеальное.

Таким образом, он не перехватывал ответ на запрос POST, он следовал некоторому перенаправлению и пытался получить ответ от другого автоматического запроса GET.

Решение заключалось в следующем: connection.setInstanceFollowRedirects(false);


Я мог узнать это, просматривая сетевой трафик с помощью сетевого монитора:

Из десктопного приложения отслеживался такой трафик:

23  10:08:50 03/10/2012 1.3944670   javaw.exe   192.168.1.36    www.XXXXXXXXX.com   HTTP    HTTP:Request, POST /es/login.php    {HTTP:8, TCP:7, IPv4:6}
24  10:08:50 03/10/2012 1.3954741   javaw.exe   192.168.1.36    www.XXXXXXXXX.com   HTTP    HTTP:HTTP Payload, URL: /es/login.php   {HTTP:8, TCP:7, IPv4:6}
32  10:08:50 03/10/2012 1.9811257   javaw.exe   www.XXXXXXXXX.com   192.168.1.36    HTTP    HTTP:Response, HTTP/1.1, Status: Moved temporarily, URL: /es/login.php  {HTTP:8, TCP:7, IPv4:6}

Для мониторинга трафика в Android-приложении мне пришлось запускать его в эмуляторе, а не в телефоне. Результат был таким:

60  9:59:34 03/10/2012  4.0285909   emulator-arm.exe    192.168.1.36    XX.XX.XXX.XXX   HTTP    HTTP:Request, POST /es/login.php    {HTTP:13, TCP:12, IPv4:11}
65  9:59:34 03/10/2012  4.1524735   emulator-arm.exe    192.168.1.36    XX.XX.XXX.XXX   HTTP    HTTP:HTTP Payload, URL: /es/login.php   {HTTP:13, TCP:12, IPv4:11}
75  9:59:35 03/10/2012  4.6276286   emulator-arm.exe    XX.XX.XXX.XXX   192.168.1.36    HTTP    HTTP:Response, HTTP/1.1, Status: Moved temporarily, URL: /es/login.php  {HTTP:13, TCP:12, IPv4:11}
77  9:59:35 03/10/2012  4.7095994   emulator-arm.exe    192.168.1.36    XX.XX.XXX.XXX   HTTP    HTTP:Request, GET /es/login.php, Query:FASID=a5e39f35325499e060f43d35bc956a45   {HTTP:13, TCP:12, IPv4:11}
311 9:59:55 03/10/2012  24.8355823  emulator-arm.exe    XX.XX.XXX.XXX   192.168.1.36    HTTP    HTTP:Response, HTTP/1.1, Status: Moved temporarily, URL: /es/login.php  {HTTP:13, TCP:12, IPv4:11}
313 9:59:55 03/10/2012  24.9384843  emulator-arm.exe    192.168.1.36    XX.XX.XXX.XXX   HTTP    HTTP:Request, GET /es/main.html, Query:FASID=a5e39f35325499e060f43d35bc956a45   {HTTP:13, TCP:12, IPv4:11}
317 9:59:55 03/10/2012  25.0535818  emulator-arm.exe    XX.XX.XXX.XXX   192.168.1.36    HTTP    HTTP:HTTP Payload, URL: /es/main.html   {HTTP:13, TCP:12, IPv4:11}

Итак, после применения **connection.setInstanceFollowRedirects(false);** результат был ожидаемым:

61  10:30:43 03/10/2012 4.9211205   emulator-arm.exe    192.168.1.36    XX.XX.XXX.XXX   HTTP    HTTP:Request, POST /es/login.php    {HTTP:14, TCP:13, IPv4:12}
64  10:30:43 03/10/2012 5.0362501   emulator-arm.exe    192.168.1.36    XX.XX.XXX.XXX   HTTP    HTTP:HTTP Payload, URL: /es/login.php   {HTTP:14, TCP:13, IPv4:12}
70  10:30:43 03/10/2012 5.5103384   emulator-arm.exe    XX.XX.XXX.XXX   192.168.1.36    HTTP    HTTP:Response, HTTP/1.1, Status: Moved temporarily, URL: /es/login.php  {HTTP:14, TCP:13, IPv4:12}

Спасибо за все ваши ответы и интерес.

person giorgiline    schedule 03.10.2012

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

person Emil Davtyan    schedule 02.10.2012
comment
Итак, что бы вы порекомендовали мне изучить? - person giorgiline; 02.10.2012
comment
Можете ли вы открыть его в мобильном браузере? - person Emil Davtyan; 02.10.2012

Убедитесь, что вы добавили необходимые разрешения в файл AndroidManifest.xml.

<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
person Bradsta    schedule 02.10.2012
comment
Проверено. Это единственные два разрешения, добавленные в манифест. - person giorgiline; 02.10.2012

У меня было много проблем с HTTPURLConnection Попробовав пару дней, я обнаружил, что порядок установки заголовков имеет значение. Вот что сработало для меня.

            conn = (HttpURLConnection) url.openConnection();
            conn.setRequestMethod("GET");
            conn.setRequestProperty("Host", "yoursite.com");
            conn.setRequestProperty("Authorization", "Basic " + Base64.encodeToString(toencode, Base64.DEFAULT));
            conn.setRequestProperty("Accept-Charset", "UTF-8");

            conn.setConnectTimeout (5000) ; 
            conn.setDoOutput(true); 
            conn.setDoInput(true); 

Это должно работать на вас.

person Kevin Rave    schedule 02.10.2012
comment
Я пробовал несколько порядков установки свойств, но, похоже, причина не в этом. - person giorgiline; 03.10.2012
comment
conn.setDoOutput(true) установит метод POST - person Mr_and_Mrs_D; 01.09.2013