OkHttp - продвинутый HTTP-клиент

Под Android имеется два стандартных HTTP-клиента: Apache HTTP Client и HttpURLConnection. Первый оптимален на старых версиях Android (Eclair and Froyo), второй - на более поздних версиях.

Библиотека OkHttp - это альтернативный HTTP-клиент, основанный на исходных кодах HttpURLConnection, и реализующий множество дополнительных полезных функций. В частности, в OkHttp:

  • добавлена поддержка протоколов HTTP 2 (draft), SPDY 3 (draft);
  • реализовано автоматическое восстановление соединения, при возникновении распространенных сетевых проблем (например, проблем c прокси-сервером и TLS рукопожатием);
  • реализован пул соединений, обеспечивающий повторное использование HTTP и SPDY соединений, за счет чего увеличивается пропускная способность и снижается время ожидания.
Важнейший плюс OkHttp - библиотека устраняет проблемы реализации HttpURLConnection на старых версиях Android. Например, прозрачная поддержка GZip реализована в HttpURLConnection только в Gingerbread (Android 2.3), кэш ответов - в Ice Cream Sandwich (Android 4.0). OkHttp предоставляет весь этот функционал, начиная с Android 2.2.

Retrofit: безопасный REST-клиент

В общем случае, при выполнении запроса к REST-серверу, требуется выполнить ряд операций:
  • сформировать URL;
  • задать HTTP-заголовки;
  • выбрать тип HTTP-запроса;
  • сформировать тело HTTP-запроса, т.е. преобразовать Java объект в JSON;
  • выполнить запрос, воспользовавшись HTTP-клиентом;
  • распарсить результаты запроса - преобразовать полученный JSON в Java объект.
Библиотека Retrofit позволяет описать все перечисленные операции с помощью аннотаций - компактно и без ошибок. Рассмотрим пример. Пусть у нас есть запрос из BooksSet REST API:
GET /books/1234
Этот запрос возвращает JSON вида
{
    "id": "1236",
    "title": "Yellow mist",
    "author": "Alexander Volkov",
    "released": "1970"
}
С помощью Retrofit мы можем описать этот запрос следующим образом:
01import retrofit.http.GET;
02import retrofit.http.Path;
03import retrofit.http.Query;
04 
05public class Book {
06  public int id;
07  public String title;
08  public String author;
09  public int released;
10}
11 
12public interface IBookSetRestAPI {
13 
14  @GET("/v1/books/{book_id}")
15  Book getBook(@Path("book_id") int book_id);
16 
17}
Выполнить запрос к серверу можно так:
1RestAdapter restAdapter = new RestAdapter.Builder()
3  .build();
4IBookSetRestAPI rest_api = restAdapter.create(IBookSetRestAPI.class);
5Book book = rest_api.getBook(136);

Каждый запрос к REST-серверу описывается отдельной функцией в интерфейсе IBookSetRestAPI. Тип HTTP запроса задается с помощью аннотаций @GET, @POST, @PUT, @DELETE, @HEAD, @PATCH, параметры URI-шаблона задаются через параметры функции и описываются аннотацией @Path.

В случае, когда в URL присутствуют переменные, они задаются через аннотацию @Query, например запросы:

GET /v1/books?limit=10&offset=20
GET /v1/books?limit=10
описываются следующим образом:
01public interface IBookSetRestAPI {
02 
03  @GET("/v1/books/{book_id}")
04  Book getBook(@Path("book_id") int book_id);
05 
06  @GET("/v1/books")
07  ListBooks getBooks(@Query("limit") int limit);
08 
09  @GET("/v1/books")
10  ListBooks getBooks(@Query("limit") int limit, @Query("offset") int offset);
11}

Разумеется, есть и другие аннотации - для задания заголовков HTTP-запросов, для формирования составных запросов и т.д.

Несмотря на то, что аннотации Retrofit по структуре похожи на аннотации JAX-RS, эти наборы аннотаций не совместимы. Причина: аннотации JAX-RS ориентированы на серверную часть, а аннотации Retrofit - на клиентскую.

Парсинг результатов

Функция Book getBook(int book_id) возвращает объект, распарсивание JSON производится автоматически. По умолчанию, для распарсивания используется GSON, т.е. в проект необходимо добавить gson-2.2.4.jar. Библиотека поддерживает кастомизацию конвертации объектов, причем конвертеры XML и Protobuf доступны вместе с библиотекой.

Можно получать результаты в "сыром", нераспарсенном виде. Достаточно определить интерфейс IBookSetRestAPI следующим способом:

01import retrofit.client.Response;
02import retrofit.http.GET;
03import retrofit.http.Path;
04import retrofit.http.Query;
05 
06public interface IBookSetRestAPI {
07 
08  @GET("/v1/books/{book_id}")
09  Response getBook(@Path("book_id") int book_id);
10 
11  @GET("/v1/books")
12  Response getBooks(@Query("limit") int limit);
13 
14  @GET("/v1/books")
15  Response getBooks(@Query("limit") int limit, @Query("offset") int offset);
16}
Объект Response дает прямой доступ к содержимому ответа сервера - можно парсить его вручную.

OkHttp и Retrofit

Retrofit выбирает HTTP-клиента следующим образом:
  • Если OkHttp задействована в проекте, то используется OkHttpClient;
  • В противном случае: если приложение работает под Android 2.2 или ниже, используется HttpClient, иначе - HttpURLConnection.

GZip и Retrofit

OkHttp использует Gzip автоматически при условии, что заголовок Accept-Encoding не задан явно. Таким образом, если Accept-Encoding не задан, то:
  • OkHttp автоматически добавляет "Accept-Encoding: gzip" и отправляет запрос серверу;
  • далее, проверяет ответ от сервера: если в заголовках ответа есть "Content-Encoding: gzip", значит данные запакованы;
  • запакованные данные OkHttp автоматически распаковывает. В результате, клиент получает Response с распакованным содержимым; если же используется конвертер, то в функцию fromBody конвертера опять же приходят уже распакованные данные.
Если же по каким-либо причинам transparent gzip необходимо отключить, то следует явно задать заголовок Accept-Encoding. Например:
1@Headers("Accept-Encoding: identity")
2@GET("/v1/books")
3ListBooks getBooks();
4 
5@Headers("Accept-Encoding: gzip")
6@GET("/v1/books")
7ListBooks getBooks2();
Запрос getBooks будет работать без gzip. Запрос getBooks2 будет поддерживать gzip, однако на выходе пользователь получит запакованные данные (как в Response, так и в функции fromBody конвертера), которые необходимо будет распаковывать вручную.

Синхронное и асинхронное выполнение запросов

Retrofit поддерживает оба варианта. Асинхронное выполнение запросов требует подключения библиотеки RxJava.

Зависимости Retrofit

Все зависимости опциональны:
  • OkHttp - если требуется OkHttpClient;
  • GSon - если планируется использовать стандартный GSon конвертер;
  • RxJava - если требуется асинхронное выполнение запросов.

Comments and questions

Publish comment or question

Copyright 2019 © ELTASK.COM
All rights reserved.