Форум программистов, компьютерный форум CyberForum.ru

Получение JSON с https сервера - Android

Войти
Регистрация
Восстановить пароль
Другие темы раздела
Android Взаимодействие с++ и Java без JNI http://www.cyberforum.ru/android-dev/thread613583.html
Необходимо сделать синтезатор речи на java, однако в адрюше 2.3 это можно сделать только на с++. Разобрался и настроил проект, который идентифицируентся как движок и С++ код отсылает пустой звук вместо речи. В принципе звук может синтезировать Java, если будет читать logcat, в который пишет из с++ текст для синтеза. Но нативный код тоже должен знать сколько времени слать пустой звук, чтобы при...
Android Создание GPS навигатора на базе Android возможно ли использовать google api maps для создания нового навигатора? http://www.cyberforum.ru/android-dev/thread613149.html
Android Dashboard
Всем добрый день. Вот возобновил изучение программирование под Android. Хочу для начала написать приложение Dashboard с нескольким кнопками. Начал с одной. Приложение скомпилировалось, но оно пустое. Не могу понять что не так. Подскажите пожалуйста! Основной файл package com.ua.workout; import android.app.Activity; import android.content.Intent; import android.os.Bundle;
Android Редактирование проекта
Доброго времени суток! В программировании для android я впервые. Писал только для windows на vb.net. Возникло желание написать лично под себя лаунчер. Но программировать для android я не умею. Я скачал исходник лаунчера (архив с исходником вложен). Но не знаю как его редактировать. Содержание исходника: Папка res Папка src Android.mk AndroidManifest.xml MODULE_LICENSE_APCHE2 NOTISE
Android Какова ориентировочная цена написания приложения для ОС Андроид? (краткое описание внутри) http://www.cyberforum.ru/android-dev/thread612093.html
Программа будет иметь простой интерфейс, по запросу пользователя отображает текст и статическую графику из базы данных на интернет сервере где информация структурированно хранится. Также пользователь может оставлять комментарии под информацией и оценки.
Android Удаление строки в ListView Приложение закрывается (ошибка) при обработке данного кода: ArrayAdapter<String> adapterlist = new ArrayAdapter<String>(this, android.R.layout.simple_list_item_1, lv_arr); listView1.setTextFilterEnabled(true); listView1.setAdapter(adapterlist); adapterlist.notifyDataSetChanged(); adapterlist.remove(adapterlist.getItem(0)); подробнее

Показать сообщение отдельно
obrazer
67 / 67 / 1
Регистрация: 04.09.2012
Сообщений: 170
08.09.2012, 19:21     Получение JSON с https сервера
Итак, покопался, поразбирался...
Вот чего собственно я хотел узнать, чтобы мне объяснили по шагам (разобрался сам, может кому пригодится):
1. Нам необходимо получить ответ от сервера с HTTPS с HTTP авторизацией. Это два раздельных процесса (моя ошибка и заключалась в том, что предположил это цельным процессом).
2. Соответственно необходимо проити проверку сертификата
3. Проверить имя хоста
4. Организовать авторизацию.

Итак, для этого...

5. Для проверки сертификата имеется множество способов, один из них приведен в примере. Вот кусок кода который отвечает за проверку:
Java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
final TrustManager[] trustAllCerts = new TrustManager[] {new X509TrustManager() {
    public X509Certificate[] getAcceptedIssuers() {
        publishProgress("getAcceptedIssuers");
         return null;
    }
    public void checkServerTrusted(X509Certificate[] chain, String authType)
            throws CertificateException {
        publishProgress("Сведения о сертификате : " + chain[0].getIssuerX500Principal().getName() + "\n Тип авторизации : " + authType);
    }
    public void checkClientTrusted(X509Certificate[] chain, String authType)
            throws CertificateException {
        publishProgress("checkClientTrusted : " + authType);
    }
} };
Этот кусок кода создает массив менеджеров проверки сертификатов и добавляет в него одну реализацию интерфейса проверки сертификата X509TrustManager. Добавлять необходимо все три метода интерфейса, хотя используется в нашем случае только один - checkServerTrusted. В нем мы можем провести проверку сертификата. Если сертификат нормальный, то метод ничего не делает (как у нас и есть), а если сертификат "плохой", то необходимо генерировать исключение (правильнее всего - CertificateException).

Видимо на этом месте барузеры проводят проверку сертификатов на надежные источники и т.п. И в том числе выдают сообщение "Сертификат безопасности этого веб-узла не был выпущен доверенным центром сертификации."

Далее получаем SSLContext и настраиваем его с помощью нашего массива менеджеров trustAllCerts. А так же получаем SSLSocketFactory.
Java
1
2
3
final SSLContext sslContext = SSLContext.getInstance("TLS");
sslContext.init( null, trustAllCerts, new java.security.SecureRandom());
final javax.net.ssl.SSLSocketFactory sslSocketFactory = sslContext.getSocketFactory();
Детально для чего и как работает вся эта конструкция я еще не разобрался, но предполагаю, что собственно это и есть классы отвечающие за создание всех объектов, проверяющих сертификаты и выполняющий все методы по созданию защищенного соединения, в том числе шифрования.

6. Создаем объект коннекта
Java
1
HttpURLConnection conn = (HttpURLConnection) new URL(url).openConnection();
И назначаем ему ранее полученный sslSocketFactory
Java
1
((HttpsURLConnection) conn).setSSLSocketFactory(sslSocketFactory);
Собственно теперь у нас есть настроеный HttpsURLConnection, который имеет фабрику SSL-сокетов для организации соединения и подключеный trustAllCerts (массив менеджеров для проверки сертификатов с созданым объектом, который и будет проверять сертификат)

Можно было бы выполнять запрос, однако у меня он далее и отбивался с оибкой "Hostname "xxxxxx" was not verified"

7. А вот для этого для мы добавляем к нашему HttpsUrlConnection-у проверку имени хоста
Java
1
2
3
4
5
((HttpsURLConnection) conn).setHostnameVerifier(new HostnameVerifier() {
    public boolean verify(String arg0, SSLSession arg1) {
        return true;
    }
});
В данном случае проверку не делаем, а подтверждаем любой хост. А можно было бы проверять на соответсвие чему-нибудь. В частности, видимо именно подобной операцией браузер проверяет соответствие сертификата и Хоста и выдает мне сообщение "Сертификат безопасности этого веб-узла был выпущен для веб-узла с другим адресом"

8. Далее настраиваем свойства коннекта
Java
1
2
3
4
5
conn.setUseCaches(false);
conn.setDoInput(true);
conn.setReadTimeout(10000 );
conn.setConnectTimeout(15000);
conn.setRequestMethod("GET");
Таймаут-ы можно не прописывать, однако в случае каких-либо проблем со связью висеть может весьма долго.
Так же как и выставление DoInput подразумевает операцию GET. Хотя я предпочитаю явно прописывать все то, что должно быть явным.

9. И вот момент указания HTTP-авторизации
Java
1
conn.setRequestProperty("Authorization", "Basic " + token);
К HTTPS-у данная операция отношения не имеет. По сути требовать авторизацию может и простой HTTP-сервер. Типов HTTP-авторизации несколько основные - Basic и Digest. В простейшем случае используется Basic, Digest - применяет некие способы шифрования.

token - логин+пароль в виде "loginassword" переведенный в последовательность байт в формате Base64. Это делается с помощью
Java
1
byte[] enc = Base64.encode("www:www".getBytes("UTF16"), Base64.DEFAULT);
Однако enc - это массив байт, а в свойство надо передавать String. И вот тут я долго воевал. Ибо приведенные везде приемы типа
Java
1
String token = enc.toString();
или просто прибавления enc к строке не работало. Как оказалось этот toString() отдает неправильное представление. Как раз на этом я и бился долго.

Случайно наткнулся на это несоответствие, поискал в интернете и нашел функцию. которая адекватно переводит в Base64-строку
Java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
    static final char base64Array [] = {
        'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H',
        'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P',
        'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X',
        'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f',
        'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n',
        'o', 'p', 'q', 'r', 's', 't', 'u', 'v',
        'w', 'x', 'y', 'z', '0', '1', '2', '3',
        '4', '5', '6', '7', '8', '9', '+', '/'
    };
 
    private static String base64Encode (String string)    {
      String encodedString = "";
      byte bytes [] = string.getBytes ();
      int i = 0;
      int pad = 0;
      while (i < bytes.length) {
        byte b1 = bytes [i++];
        byte b2;
        byte b3;
        if (i >= bytes.length) {
           b2 = 0;
           b3 = 0;
           pad = 2;
           }
        else {
           b2 = bytes [i++];
           if (i >= bytes.length) {
              b3 = 0;
              pad = 1;
              }
           else
              b3 = bytes [i++];
           }
        byte c1 = (byte)(b1 >> 2);
        byte c2 = (byte)(((b1 & 0x3) << 4) | (b2 >> 4));
        byte c3 = (byte)(((b2 & 0xf) << 2) | (b3 >> 6));
        byte c4 = (byte)(b3 & 0x3f);
        encodedString += base64Array [c1];
        encodedString += base64Array [c2];
        switch (pad) {
         case 0:
           encodedString += base64Array [c3];
           encodedString += base64Array [c4];
           break;
         case 1:
           encodedString += base64Array [c3];
           encodedString += "=";
           break;
         case 2:
           encodedString += "==";
           break;
         }
        }
        return encodedString;
    }
Вероятно, я чего-то недогоняю с классом Base64. Подскажите где ошибка. С приведенной выше функцией все заработало.

10. Ну и собственно момент подключения. В отличие от ранее приведенного примера, где сразу производится попытка чтения из потока, правильнее выполнять код, по проверке состояния ответа (response)
Java
1
2
3
if (conn.getResponseCode() != HttpURLConnection.HTTP_OK) {
    throw new Exception("http error : " + conn.getResponseCode());
}
Вот как раз моя ошибка на попытке обращении к потоку (FileNotFoundException) была следствием отсутствия потока, ввиду того, что в ответе response была та или иная HTTP-ошибка. Например, если убрать добавление свойтсва авторизации к HttpsURLConnection, сервер возвращает 401 - требуется авторизация, 403 - в случае ошибки авторизации и т.п.
В данном обработчике можно поставить соответствующую реакцию на ответ сервера

11. Ну и если ответ сервера все же HTTP_OK, то можно обрабатывать результат приведенным в примере способом
Java
1
2
3
4
5
6
7
BufferedReader in = new BufferedReader(new InputStreamReader(conn.getInputStream()));
String nextLine = null;
while ((nextLine = in.readLine()) != null) {
    sb.append(nextLine);
}
in.close();
conn.disconnect();
Все, данные получены!

Это чисто моё изучение материала. Однако решил сюда написать, потому как подробно по шагам, что для чего... Такого описания я так нигде и не нашел. Может кому пригодится еще.

Если где ошибся - поправьте, может и дополните чем полезным
 
Текущее время: 02:19. Часовой пояс GMT +3.
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin® Version 3.8.9
Copyright ©2000 - 2017, vBulletin Solutions, Inc.
Рейтинг@Mail.ru