Урок 15. Знакомство с HTTP. HtppUrlConnection, метод для считывания данных о пользователе
Знакомство с HTTP
Для обмена сообщениями с сервером мы будем использовать протокол HTTP. Это очень знаменитый протокол, который используются в модели клиент-серверной архитектуры. Более подробное описание протокола вы можете посмотреть здесь.
Для того, чтобы использовать этот протокол нам необходимо знать адрес сервера, для того, чтобы отправлять запросы.
Все методы, которые предоставляет twitter-api описаны здесь. Обычно все методы, которые предоставляет какой-то компонент называют API. Далее я буду использовать этот термин.
Мы сегодня напишем запрос для метода users.show. Этот метод позволит нам отобразить информацию о пользователе.
Давайте прочитаем документацию метода.
Мы можем увидеть, что:
Этот метод имеет тип GET, что означает, что мы считываем информацию.
Метод называется users/show. Это указано после слова GET.
Для запроса нам надо передать серверу параметр user_id или screen_name. Мы воспользуемся параметром user_id, т.к. мы передаём его на экран UserInfoActivity.
Видим адрес для запроса https://api.twitter.com/1.1/users/show.json. Нам надо точно его знать, чтобы мы могли послать запрос по нужному адресу и получить ответ.
В блоке ResourceInformation видим:
Response formats – JSON. Указывает, что сервер отвечает в формате JSON. Об этом формате мы поговорим в следующем уроке.
Requires authentication? Yes. Указывает, что метод требует авторизацию пользователя.
Rate limited? Yes. Указывает, что есть ограничения по количеству запросов.
Requests / 15-min window (user auth) – 900. Указывает, что можно посылать не более, чем 900 запросов в 15 минут для авторизованного пользователя (наш случай).
Requests / 15-min window (app auth) – 900. Указывает, что можно посылать не более, чем 900 запросов в 15 минут для авторизованного приложения (не наш случай). Есть отдельная авторизация, как приложения, при которой не надо указывать данные пользователя. Мы её не будем использовать, т.к. она добавляет дополнительные ограничения.
Следующий блок Parameters:
user_id – id пользователя информацию о котором мы хотим получить. Поле отмечено как required (обязательное).
screen_name – это имя, которое отображается в каждом аккаунте. Оно тоже отмечено, как required (обязательное).
include_entities – boolean, значение, которое описывает конфигурацию ответа. Если передаём значение true, то сервер добавит в ответ объект entities с дополнительными вложенными объектами. Поле отмечено как optional(опциональное). Т.е. мы можем его не передавать.
С этим разобрались. Нам для запроса надо передать параметром либо user_id, либо screen_name. Эти параметры мы будем передавать как часть запроса (query params).
В блоке Example Requests на картинке мы видим запрос GET https://api.twitter.com/1.1/users/show.json?screen_name=twitterdev. Давайте разберём его по частям:
GET – тип метода. Обозначает, что мы считываем данные, а не обновляем их.
https://api.twitter.com/1.1/users/show.json – адрес метода. Он должен всегда оставаться в таком виде.
?screen_name=twitterdev – здесь происходит передача параметров для запроса. Это можно понять по знаку ?. Всё, что передаётся после него относится к параметрам в запросе. В данном примере передаётся параметр screen_name, значение его передаётся после знака = (twitterdev).
Давайте попробуем составим наш запрос. В качестве параметра будем передавать user_id, а не screen_name. Допустим, наш id равен 1234. Тогда запрос будет выглядеть так: GET https://api.twitter.com/1.1/users/show.json?user_id=1234. Если мы ходим передать ещё один параметр include_entities, то надо добавить символ & (shift + 7) между параметрами. Запрос с двумя параметрами выглядит так:
GET https://api.twitter.com/1.1/users/show.json?user_id=1234&include_entities=false
Перед тем, как перейти к реализации HTTP в Android остановимся на удобной console для тестирования большинства популярных API (в том числе twitter). С её помощью можно убедиться, что запрос к серверу составлен верно.
Обратим внимание на левую часть – там отображаются все методы, которые доступы в Twitter API. В окно ввода Select an API method давайте введём название нашего метода users/show и нажмём, чтобы показать дополнительную информацию и о нём.
После нажатия на метод, видим, что открылось окно, куда надо ввести параметры для запроса.
Вначале надо добавить данные об авторизации, т.к. метод требует авторизацию пользователя.
Для этого давайте нажмём на кнопку в блоке Authentication и выберем пункт OAuth 1.
В контекстном окне нажимаем Sign in with Twitter. В следующем окне нажимаем кнопку Authorize app.
После этого нас перенаправит на сайт консоли и в блоке Authentication появится наша информация об авторизации.
Если выбранный до этого метод сбился, то найдите в списке методов users/show и нажмите на него, чтобы перейти в детальную информацию.
Давайте добавим в форму user_id значение 929257819349700608. Это идентификатор аккаунта colibri-tweet, будем использовать его для теста. В нашем реальном приложениии мы будем брать id динамически после авторизации пользователя. После того, как мы ввели значение и нажали кнопку Send, экран выглядит следующим образом:
Блок Request
Давайте обратим внимание в первую очередь на блок Request в левом нижнем углу. Обратим внимание на первые две строки:
GET /1.1/users/show.json?user_id=929257819349700608 HTTP/1.1 – информация о запросе. Похоже на то, что мы разбирали до этого. Только адрес сервера выводится не полностью, но это не проблема. Видим, что параметр передаётся после знака ?, как мы уже видели. Также видим, что используется протокол HTTP/1.1
Authorization – header , в котором передаётся информация об авторизованном пользователе. Если бы мы не прошли процесс авторизации, то сервер бы ответил нам с ошибкой.
Блок Response
Блок Response находится в правом нижнем углу. Давайте рассмотрим первую строку ответа:
HTTP/1.1 200 OK – информация об ответе. HTTP/1.1 – версия протокола, 200 OK – статус ответа сервера, означающий, что запрос успешно обработан. Подробнее о всех статусах HTTP протокола можно почитать здесь
Также пролистаем этот блок в самый низ и увидим сам ответ в формате JSON.
Копирование, форматирование ответа от сервера
В таком виде ответ не годится для понимания. Чтобы выделить всю строку целиком, давайте выделим начало строки и нажмём кнопки shift + end. После этого копируем выделенную строку и переходим на сайт форматирования JSON. Например на этот. Вставляем скопированную строку в левую область экрана и нажимаем кнопку Beautify
Это и есть ответ, который нам послал сервер.
Давайте теперь попробуем повторить эти же самые действия, только в нашем приложении, используя java код.
Использование HttpUrlConnection.
В Android есть встроенный класс, который помогает работать с протоколом HTTP. Этот класс называется HttpUrlConnection. Сейчас есть более высокоуровневые библиотеки типа OkHttp, Retrofit, но знакомство с HTTP протоколом лучше начать именно с низкоуровневого подхода. Библиотеки же мы рассмотрим в будущих модулях.
Давайте создадим новый пакет, который назовём network. Создадим класс HttpClient, добавим в него один метод, который назовём readUserInfo(long userId).
Первое, что нам надо сделать – это составить адрес запроса в формате, описанном выше. Он должен выглядеть следующим образом: https://api.twitter.com/1.1/users/show.json?user_id=1234. Нам необходимо динамически подставлять в запрос userId, который поступает в метод параметром. Теперь наш метод выглядит так:
Теперь нам надо отправить запрос серверу по этому адресу.
Отправление запроса серверу
Чтобы отправить запрос нам надо открыть подключение к серверу, после чего считать данные, которые он нам пришлёт в ответ. Давайте откроем подключение к серверу.
Важно, что эти методы могут выбрасывать исключения. Поэтому необходимо либо обернуть этот код в блок try, catch, либо добавить в сигнатуру метода throws IOException, чтобы избежать ошибок компиляции. Тогда код, который будет вызывать этот метод обязан будет обработать исключения. Мы выбрали второй вариант, чтобы клиентский код сам обрабатывал ошибки.
Помните, что метод не работает без информации об авторизации? Мы должны добавить эту информацию в наш запрос во время подключения. Помним, что библиотека tiwtter-kit хранит данные о пользователе, поэтому в методе getAuthHeader() мы просто используем её. Можете просто скопировать этот метод и его использование. На данном этапе обучения эта информация не является важной. После добавления метода и его использования код выглядит так:
Видим, что добавился метод getAuthHeader(String url), который отдаёт нам информацию об авторизации, которую необходимо указать при запросе.
В методе readUserInfo() мы используем эту информацию с помощью connection.setRequestProperty(HEADER_AUTHORIZATION, authHeader). На этом этапе достаточно понимать, что данный код добавляет в запрос информацию об авторизации пользователя, которая необходима для работы метода.
Считывание ответа от сервера
Алгоритм считывания ответа такой:
Смотрим статус подключения
Получаем входной поток данных от нашего объекта connection. Если статус отличается от статуса 200, то мы считываем поток ошибок, иначе поток корректного ответа.
После этого нам необходимо преобразовать поток данных типа InputStream к привычному нам формату String. Это мы сделаем используя функцию convertStreamToString(InputStream stream).
publicclassHttpClient{public String readUserInfo(long userId)throws IOException {// остальной код выше не изменился
InputStream in;int status = connection.getResponseCode();if(status != HttpURLConnection.HTTP_OK){
in = connection.getErrorStream();}else{
in = connection.getInputStream();}
String response = convertStreamToString(in);return response;}private String convertStreamToString(InputStream stream)throws IOException {
BufferedReader reader =new BufferedReader(new InputStreamReader(stream));
StringBuilder sb =new StringBuilder();
String line;while((line = reader.readLine())!=null){
sb.append(line).append("\n");}
stream.close();return sb.toString();}// остальной код ниже не изменился}
Суть работы метода convertStreamToString(InputStream stream) заключается в том, что он пробегается по каждой строке потока данных InputStream и записывает их в наш строку, добавляя переносы строк. На выходе получим обыкновенную строку типа String.
Вот и всё, теперь мы реализовали с вами наш первый HTTP метод.
Если что-то сейчас осталось непонятным, то не беспокойтесь. В этом модуле мы ещё напишем с вами не один метод, что поможет вам усвоить материал на практике.
Использование в UserInfoActivity
Давайте теперь выведем в log ответ метода. Напомним, что запросы в сеть являются тяжёлой операцией, поэтому нам нужно делать всю эту работу не в UI потоке. Для этого мы будем использовать класс AsyncTask. Пополнить или освежить свои знания можно посмотрев этот урок.
Давайте добавим объект HttpClient в UserInfoActivity и немного изменим метод loadUserInfo(). Помним, что в прошлом уроке мы написали код, который достаёт из Intentid пользователя, переданного с экрана AuthActivity или SearchUsersActivity. Давайте будем передавать этот id в качестве параметра метода loadUserInfo().
publicclassUserInfoActivityextends AppCompatActivity {// остальной код выше не изменилсяprivate HttpClient httpClient;
@Override
protectedvoidonCreate(Bundle savedInstanceState){// остальной код выше не изменился
httpClient =new HttpClient();
loadUserInfo(userId);
loadTweets();}privatevoidloadUserInfo(Long userId){new AsyncTask<Void, Void, String>(){
@Override
protected String doInBackground(Void... voids){try{return httpClient.readUserInfo(userId);}catch(IOException e){
e.printStackTrace();returnnull;}}
@Override
protectedvoidonPostExecute(String response){
Log.d("HttpTest", response);}}.execute();}}
AndroidStudio выделяет код Asynctask, сообщая о проблеме утечки памяти. Пока просто игнорируем это, а в дальнейшем исправим это замечание. Мы можем нажать сочетание клавиш Alt + Enter и выбрать пункт Suppress: Add @SuppressLint("StaticFieldLeak") annotation. Этим мы говорим, чтобы анализатор кода игнорировал это замечание. После этого над нашим методом появится аннотация @SuppressLint("StaticFieldLeak").
Запустим наше приложение и посмотрим, что же мы получили в логах.
Обязательно в имени фильтра введите HttpTest, чтобы увидеть только тот лог, который мы выводим внутри AsyncTask. Видим, что нам пришёл ответ. Давайте скопируем его и посмотрим содержимое. Повторяем все действия, которые уже проделывали в блоке [Копирование, форматирование ответа от сервера]. После чего видим, что наш ответ выглядит так:
Мы получили такой же ответ, как через консоль. Поздравляем, сегодня мы изучили с вами самую сложную тему этого модуля. Следующие уроки помогут закрепить вам полученные знания на практике.
Сайт использует cookie-файлы для того, чтобы вам было удобнее им пользоваться. Для
продолжения работы с сайтом, вам необходимо принять использование cookie-файлов.
Знакомство с HTTP
Для обмена сообщениями с сервером мы будем использовать протокол
HTTP
. Это очень знаменитый протокол, который используются в модели клиент-серверной архитектуры. Более подробное описание протокола вы можете посмотреть здесь.Для того, чтобы использовать этот протокол нам необходимо знать адрес сервера, для того, чтобы отправлять запросы.
Все методы, которые предоставляет
twitter-api
описаны здесь. Обычно все методы, которые предоставляет какой-то компонент называютAPI
. Далее я буду использовать этот термин.Мы сегодня напишем запрос для метода users.show. Этот метод позволит нам отобразить информацию о пользователе.
Давайте прочитаем документацию метода.
Мы можем увидеть, что:
GET
, что означает, что мы считываем информацию.users/show
. Это указано после словаGET
.user_id
илиscreen_name
. Мы воспользуемся параметромuser_id
, т.к. мы передаём его на экранUserInfoActivity
.https://api.twitter.com/1.1/users/show.json
. Нам надо точно его знать, чтобы мы могли послать запрос по нужному адресу и получить ответ.В блоке
ResourceInformation
видим:JSON
. Указывает, что сервер отвечает в форматеJSON
. Об этом формате мы поговорим в следующем уроке.900
. Указывает, что можно посылать не более, чем 900 запросов в 15 минут для авторизованного пользователя (наш случай).900
. Указывает, что можно посылать не более, чем 900 запросов в 15 минут для авторизованного приложения (не наш случай). Есть отдельная авторизация, как приложения, при которой не надо указывать данные пользователя. Мы её не будем использовать, т.к. она добавляет дополнительные ограничения.Следующий блок
Parameters
:user_id
–id
пользователя информацию о котором мы хотим получить. Поле отмечено какrequired
(обязательное).screen_name
– это имя, которое отображается в каждом аккаунте. Оно тоже отмечено, какrequired
(обязательное).include_entities
–boolean
, значение, которое описывает конфигурацию ответа. Если передаём значениеtrue
, то сервер добавит в ответ объектentities
с дополнительными вложенными объектами. Поле отмечено какoptional
(опциональное). Т.е. мы можем его не передавать.С этим разобрались. Нам для запроса надо передать параметром либо
user_id
, либоscreen_name
. Эти параметры мы будем передавать как часть запроса (query params
).В блоке
Example Requests
на картинке мы видим запросGET https://api.twitter.com/1.1/users/show.json?screen_name=twitterdev
. Давайте разберём его по частям:GET
– тип метода. Обозначает, что мы считываем данные, а не обновляем их.https://api.twitter.com/1.1/users/show.json
– адрес метода. Он должен всегда оставаться в таком виде.?screen_name=twitterdev
– здесь происходит передача параметров для запроса. Это можно понять по знаку?
. Всё, что передаётся после него относится к параметрам в запросе. В данном примере передаётся параметрscreen_name
, значение его передаётся после знака=
(twitterdev
).Давайте попробуем составим наш запрос. В качестве параметра будем передавать
user_id
, а неscreen_name
. Допустим, нашid
равен1234
. Тогда запрос будет выглядеть так:GET https://api.twitter.com/1.1/users/show.json?user_id=1234
. Если мы ходим передать ещё один параметрinclude_entities
, то надо добавить символ&
(shift + 7
) между параметрами. Запрос с двумя параметрами выглядит так:GET https://api.twitter.com/1.1/users/show.json?user_id=1234&include_entities=false
Перед тем, как перейти к реализации
HTTP
вAndroid
остановимся на удобнойconsole
для тестирования большинства популярныхAPI
(в том числеtwitter
). С её помощью можно убедиться, что запрос к серверу составлен верно.Работа с консолью Twitter API
Давайте перейдём по ссылке.
Выглядит консоль так:
Обратим внимание на левую часть – там отображаются все методы, которые доступы в
Twitter API
. В окно вводаSelect an API method
давайте введём название нашего методаusers/show
и нажмём, чтобы показать дополнительную информацию и о нём.После нажатия на метод, видим, что открылось окно, куда надо ввести параметры для запроса.
Вначале надо добавить данные об авторизации, т.к. метод требует авторизацию пользователя.
Для этого давайте нажмём на кнопку в блоке
Authentication
и выберем пунктOAuth 1
.В контекстном окне нажимаем
Sign in with Twitter
. В следующем окне нажимаем кнопкуAuthorize app
.После этого нас перенаправит на сайт консоли и в блоке
Authentication
появится наша информация об авторизации.Если выбранный до этого метод сбился, то найдите в списке методов
users/show
и нажмите на него, чтобы перейти в детальную информацию.Давайте добавим в форму
user_id
значение929257819349700608
. Это идентификатор аккаунтаcolibri-tweet
, будем использовать его для теста. В нашем реальном приложениии мы будем братьid
динамически после авторизации пользователя. После того, как мы ввели значение и нажали кнопкуSend
, экран выглядит следующим образом:Блок
Request
Давайте обратим внимание в первую очередь на блок
Request
в левом нижнем углу. Обратим внимание на первые две строки:GET /1.1/users/show.json?user_id=929257819349700608 HTTP/1.1
– информация о запросе. Похоже на то, что мы разбирали до этого. Только адрес сервера выводится не полностью, но это не проблема. Видим, что параметр передаётся после знака?
, как мы уже видели. Также видим, что используется протоколHTTP/1.1
Authorization
– header , в котором передаётся информация об авторизованном пользователе. Если бы мы не прошли процесс авторизации, то сервер бы ответил нам с ошибкой.Блок
Response
Блок
Response
находится в правом нижнем углу. Давайте рассмотрим первую строку ответа:HTTP/1.1 200 OK
– информация об ответе.HTTP/1.1
– версия протокола,200 OK
– статус ответа сервера, означающий, что запрос успешно обработан. Подробнее о всех статусахHTTP
протокола можно почитать здесьТакже пролистаем этот блок в самый низ и увидим сам ответ в формате
JSON
.Копирование, форматирование ответа от сервера
В таком виде ответ не годится для понимания. Чтобы выделить всю строку целиком, давайте выделим начало строки и нажмём кнопки
shift + end
. После этого копируем выделенную строку и переходим на сайт форматированияJSON
. Например на этот. Вставляем скопированную строку в левую область экрана и нажимаем кнопкуBeautify
Это и есть ответ, который нам послал сервер.
Давайте теперь попробуем повторить эти же самые действия, только в нашем приложении, используя
java
код.Использование
HttpUrlConnection
.В
Android
есть встроенный класс, который помогает работать с протоколомHTTP
. Этот класс называетсяHttpUrlConnection
. Сейчас есть более высокоуровневые библиотеки типаOkHttp
,Retrofit
, но знакомство сHTTP
протоколом лучше начать именно с низкоуровневого подхода. Библиотеки же мы рассмотрим в будущих модулях.Давайте создадим новый пакет, который назовём
network
. Создадим классHttpClient
, добавим в него один метод, который назовёмreadUserInfo(long userId)
.Реализация выглядит так:
HtppClient.java
Составление адреса запроса
Первое, что нам надо сделать – это составить адрес запроса в формате, описанном выше. Он должен выглядеть следующим образом:
https://api.twitter.com/1.1/users/show.json?user_id=1234
. Нам необходимо динамически подставлять в запросuserId
, который поступает в метод параметром. Теперь наш метод выглядит так:HtppClient.java
Теперь нам надо отправить запрос серверу по этому адресу.
Отправление запроса серверу
Чтобы отправить запрос нам надо открыть подключение к серверу, после чего считать данные, которые он нам пришлёт в ответ. Давайте откроем подключение к серверу.
HtppClient.java
Важно, что эти методы могут выбрасывать исключения. Поэтому необходимо либо обернуть этот код в блок
try, catch
, либо добавить в сигнатуру методаthrows IOException
, чтобы избежать ошибок компиляции. Тогда код, который будет вызывать этот метод обязан будет обработать исключения. Мы выбрали второй вариант, чтобы клиентский код сам обрабатывал ошибки.Подробнее про исключения здесь.
Добавление информации об авторизации пользователя
Помните, что метод не работает без информации об авторизации? Мы должны добавить эту информацию в наш запрос во время подключения. Помним, что библиотека
tiwtter-kit
хранит данные о пользователе, поэтому в методеgetAuthHeader()
мы просто используем её. Можете просто скопировать этот метод и его использование. На данном этапе обучения эта информация не является важной. После добавления метода и его использования код выглядит так:HtppClient.java
Видим, что добавился метод
getAuthHeader(String url)
, который отдаёт нам информацию об авторизации, которую необходимо указать при запросе.В методе
readUserInfo()
мы используем эту информацию с помощьюconnection.setRequestProperty(HEADER_AUTHORIZATION, authHeader)
. На этом этапе достаточно понимать, что данный код добавляет в запрос информацию об авторизации пользователя, которая необходима для работы метода.Считывание ответа от сервера
Алгоритм считывания ответа такой:
connection
. Если статус отличается от статуса 200, то мы считываем поток ошибок, иначе поток корректного ответа.InputStream
к привычному нам форматуString
. Это мы сделаем используя функциюconvertStreamToString(InputStream stream)
.Так всё это выглядит в
java
коде:HtppClient.java
Суть работы метода
convertStreamToString(InputStream stream)
заключается в том, что он пробегается по каждой строке потока данныхInputStream
и записывает их в наш строку, добавляя переносы строк. На выходе получим обыкновенную строку типаString
.Вот и всё, теперь мы реализовали с вами наш первый
HTTP
метод.Если что-то сейчас осталось непонятным, то не беспокойтесь. В этом модуле мы ещё напишем с вами не один метод, что поможет вам усвоить материал на практике.
Использование в UserInfoActivity
Давайте теперь выведем в
log
ответ метода. Напомним, что запросы в сеть являются тяжёлой операцией, поэтому нам нужно делать всю эту работу не вUI
потоке. Для этого мы будем использовать классAsyncTask
. Пополнить или освежить свои знания можно посмотрев этот урок.Давайте добавим объект
HttpClient
вUserInfoActivity
и немного изменим методloadUserInfo()
. Помним, что в прошлом уроке мы написали код, который достаёт изIntent
id
пользователя, переданного с экранаAuthActivity
илиSearchUsersActivity
. Давайте будем передавать этотid
в качестве параметра методаloadUserInfo()
.UserInfoActivity.java
AndroidStudio
выделяет кодAsynctask
, сообщая о проблеме утечки памяти. Пока просто игнорируем это, а в дальнейшем исправим это замечание. Мы можем нажать сочетание клавишAlt + Enter
и выбрать пунктSuppress: Add @SuppressLint("StaticFieldLeak") annotation
. Этим мы говорим, чтобы анализатор кода игнорировал это замечание. После этого над нашим методом появится аннотация@SuppressLint("StaticFieldLeak")
.Запустим наше приложение и посмотрим, что же мы получили в логах.
Обязательно в имени фильтра введите
HttpTest
, чтобы увидеть только тот лог, который мы выводим внутриAsyncTask
. Видим, что нам пришёл ответ. Давайте скопируем его и посмотрим содержимое. Повторяем все действия, которые уже проделывали в блоке [Копирование, форматирование ответа от сервера]. После чего видим, что наш ответ выглядит так:Мы получили такой же ответ, как через консоль. Поздравляем, сегодня мы изучили с вами самую сложную тему этого модуля. Следующие уроки помогут закрепить вам полученные знания на практике.
Полный листинг кода:
HttpClient.java
UserInfoActivity.java
Подведём итоги:
HTTP
протокол часто используется для общения клиент-серверных приложений.API
, используя веб-консоль, чтобы понять, как именно работаетAPI
.HTTP
вAndroid
довольно низкоуровневая. Но стоит знать, что реализоватьHTTP
можно и не используя сторонних библиотек.