Форум программистов, компьютерный форум, киберфорум
Наши страницы
Программирование Android
Войти
Регистрация
Восстановить пароль
Другие темы раздела
Программирование Android Взаимодействие с++ и Java без JNI http://www.cyberforum.ru/android-dev/thread613583.html
Необходимо сделать синтезатор речи на java, однако в адрюше 2.3 это можно сделать только на с++. Разобрался и настроил проект, который идентифицируентся как движок и С++ код отсылает пустой звук...
Создание GPS навигатора на базе Android Программирование Android
возможно ли использовать google api maps для создания нового навигатора?
Программирование Android Dashboard
Всем добрый день. Вот возобновил изучение программирование под Android. Хочу для начала написать приложение Dashboard с нескольким кнопками. Начал с одной. Приложение скомпилировалось, но оно...
Программирование Android Редактирование проекта Доброго времени суток! В программировании для android я впервые. Писал только для windows на vb.net. Возникло желание написать лично под себя лаунчер. Но программировать для android я не умею. Я... http://www.cyberforum.ru/android-dev/thread612126.html
Программирование 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); ...
Программирование Android ошибка Power Manager
Здравствуйте, подскажите как понять где проблема - в логах выдает ошибку через несколько секунд после старта программы... на андроиде также вылетает ошибка... 06-22 04:35:08.462:...
Программирование Android по нажатию на кнопку повернуть экран (из портретного в ландшафтный, потом наоборот) Только начинаю осваивать. Как по нажатию на кнопку сменить ориентацию экрана? http://www.cyberforum.ru/android-dev/thread610880.html
Программирование Android Поворот Экрана http://www.cyberforum.ru/android-dev/thread610847.html
У меня есть TableLayout и матрица смолл кнопок 8 на 8 описанных через XML. При повороте экрана часть кнопок не видно. Как можно описать, чтобы для любых видов экранов состояние сохранялось и все...
Программирование Android Пример выполнения (HTTP) запроса к веб-сервису и разбор ответа Здравствуйте! Просмотрев кучу форумов и прочитав много статей, не нашёл ответа на вопрос как создать приложение в Андроид которое будет работать по схеме HTTP запросов. Дайте пожалуйста пример... http://www.cyberforum.ru/android-dev/thread610641.html
obrazer
71 / 71 / 3
Регистрация: 04.09.2012
Сообщений: 170
08.09.2012, 19:21 0

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

08.09.2012, 19:21. Просмотров 6932. Ответов 15
Метки (Все метки)

Ответ

Итак, покопался, поразбирался...
Вот чего собственно я хотел узнать, чтобы мне объяснили по шагам (разобрался сам, может кому пригодится):
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();
Все, данные получены!

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

Если где ошибся - поправьте, может и дополните чем полезным

Вернуться к обсуждению:
Получение JSON с https сервера
3
Answers
Эксперт
37091 / 29110 / 5898
Регистрация: 17.06.2006
Сообщений: 43,301
08.09.2012, 19:21

Парсинг JSON ответа от сервера
Здравствуйте друзья, давно не заходил к вам в гости. Столкнулся с таким интересным (интересно...

Получение json строки и ее вывод в консоль
Доброго времени суток. Знаю, что в интернете полно ресурсов на тему json, но не могу найти...

Как правильно парсить json с сервера
Здравствуйте. У меня есть JSON, полученный с сервера, имеет приблизительно такой вид: ...

0
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin® Version 3.8.9
Copyright ©2000 - 2019, vBulletin Solutions, Inc.
Рейтинг@Mail.ru