Статьи

HTTP-клиент Android Apache

В этом посте я хочу описать, как создать HTTP-клиент с использованием библиотеки Apache . В одном из моих постов я описываю, как мы можем использовать HttpUrlConnection для создания клиента. Используя библиотеку Apache, я хочу объяснить, как мы можем сделать POST-запрос , загрузить изображения и загрузить многочастные двоичные данные . Более того, я опишу, как обмениваться куки. Итак, темы:

  • POST запрос
  • скачать двоичные данные
  • загрузить двоичные данные
  • обмен куки

Библиотека Apache — это внешняя библиотека, поставляемая с Android SDK, которая упрощает задачу выполнения HTTP-запроса.

POST запрос

Как мы уже знаем, POST и GET являются основным методом, который мы можем использовать для обмена данными с удаленным сервером. В качестве примера я отправлю на удаленный сервер некоторые данные в текстовом формате (на данный момент). Итак, первый шаг — создание DefaultHttpClient, который используется как оболочка для отправки данных.

1
HttpClient client = new DefaultHttpClient();

Получив наш клиент, мы должны создать экземпляр класса, который обрабатывает POST-запрос:

1
HttpPost post = new HttpPost(url);

где url — это URL, который мы хотим вызвать. Для отправки данных нам просто нужно создать список
NameValuePair простой класс, который содержит имя и значение наших параметров, которые мы хотим отправить.

1
2
3
4
List<NameValuePair> nvList = new ArrayList<NameValuePair>();
BasicNameValuePair bnvp = new BasicNameValuePair("name", name);
// We can add more
nvList.add(bnvp);

В этом случае в строке 2 мы устанавливаем имя параметра как имя и добавляем bnvp в список, как сказано выше. Теперь мы создали наш список и установили его внутри нашего почтового запроса, чтобы его можно было отправить:

1
post.setEntity(new UrlEncodedFormEntity(nvList));

В этом случае мы кодируем наши параметры, используя кодировку Url. Последний шаг — выполнение запроса через наш экземпляр DefaultHttpClient. В результате мы получаем HttpResponse, который можно использовать для чтения результата нашего запроса:

1
HttpResponse resp = client.execute(post);

Чтобы прочитать ответ, мы можем получить InputStream (строка 1) и использовать его для чтения данных следующим образом:

1
2
3
4
5
6
7
8
9
InputStream is  = resp.getEntity().getContent();           
BufferedReader reader = new BufferedReader(new InputStreamReader(is));
StringBuilder str = new StringBuilder();
String line = null;
while((line = reader.readLine()) != null){
    str.append(line + "\n");
}
is.close();
buffer.append(str.toString());

В конце у нас есть строка, которую мы можем использовать для обновления нашего интерфейса.

Мы должны помнить, что эта операция может занимать много времени, поэтому мы должны выполнить этот запрос в AsyncTask . Для получения дополнительной информации прочитайте пост « Android HTTP-клиент: GET, POST, Download, Upload, Multipart Request ». Достаточно сказать, что все, что мы уже сделали, должно быть внутри метода doInBackground . Запустив пример, который мы имеем:

Серверная сторона android_http_apache_client_server

Скачать двоичные данные

Еще одна распространенная операция — загрузка двоичных данных с сервера. В этом случае мы хотим загрузить изображение с сервера и показать его в нашем пользовательском интерфейсе.

Операция очень проста, потому что в этом случае мы должны сделать запрос HTTP Post, передав имя изображения (строка 7-10) и прочитав двоичный ответ (строка 15-28):

01
02
03
04
05
06
07
08
09
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
@Override
protected byte[] doInBackground(String... params) {
    String url = params[0];
    String name = params[1];
 
    HttpClient client = new DefaultHttpClient();
    HttpPost post = new HttpPost(url);
    List<NameValuePair> paramList = new ArrayList<NameValuePair>();
    paramList.add(new BasicNameValuePair("name", name));
    byte[] data = null;
 
    try {
        post.setEntity(new UrlEncodedFormEntity(paramList));
        HttpResponse resp = client.execute(post);
        InputStream is = resp.getEntity().getContent();
        int contentSize = (int) resp.getEntity().getContentLength();
        System.out.println("Content size ["+contentSize+"]");
        BufferedInputStream bis = new BufferedInputStream(is, 512);
 
        data = new byte[contentSize];
        int bytesRead = 0;
        int offset = 0;
 
        while (bytesRead != -1 && offset < contentSize) {
            bytesRead = bis.read(data, offset, contentSize - offset);
            offset += bytesRead;
        }
    }
    catch(Throwable t) {
        // Handle error here
        t.printStackTrace();
    }
 
    return data;
}

В строке 17 мы читаем длину ответа, чтобы мы могли создать байтовый массив с таким же размером (см. Строку 21), затем в строке 19 мы создаем буферизованный входной поток для чтения потока ответа. Затем мы просто читаем ответ, заполняющий массив байтов данных. В результате мы имеем:

Загрузить двоичные данные

Это один из самых интересных аспектов. Для выполнения этой операции нам нужно добавить внешнюю библиотеку, чтобы упростить задачу. Это недостаток использования http-клиента apache по отношению к нативному api для Android. С другой стороны, как мы видели, Android Api не обрабатывает многочастные запросы, поэтому мы должны делать все с нуля. Используя эту библиотеку, мы можем упростить процесс, но в результате мы получаем больший apk. Библиотека имеет открытый исходный код и называется httpmime-xxx.jar . Вы можете скачать его здесь . Не забудьте добавить его в свой проект и его необходимо экспортировать (см. «Порядок и экспорт в Eclipse»). В качестве примера мы создаем многочастный запрос, содержащий некоторые текстовые данные и изображение. Поэтому мы всегда начинаем создавать DefaultHttpClient и HttpPost:

1
2
HttpClient client = new DefaultHttpClient();
HttpPost post = new HttpPost(url);

Теперь нам нужно создать содержимое нашего поста под названием Entity:

1
MultipartEntity multiPart = new MultipartEntity();

и затем добавьте отдельные части: две — текстовые данные, а одна — двоичные данные (изображение, которое мы хотим загрузить):

1
2
3
multiPart.addPart("param1", new StringBody(param1));
multiPart.addPart("param2", new StringBody(param2));
multiPart.addPart("file", new ByteArrayBody(baos.toByteArray(), "logo.png"));

Обратите внимание, что в строке 3 мы создаем деталь, используя ByteArrayBody для хранения двоичных данных. Мы заполняем содержание публикации данными, которые мы создали:

1
post.setEntity(multiPart);

а затем мы просто отправляем (или публикуем) его на сервер:

1
client.execute(post);

Запустив приложение мы имеем:

android_http_apache_client_upload Серверная сторона android_http_apache_client_upload_server

Обмен куки

Одним интересным аспектом протокола HTTP является управление файлами cookie . Как мы знаем, HTTP — это протокол без сохранения состояния, поэтому, используя куки, мы можем сохранять некоторую информацию в HTTP-запросах. В качестве примера мы можем предположить сделать два HTTP-запроса: один, где мы вызываем URL, а сервер возвращает cookie, содержащий некоторую информацию, и другой, где мы отправляем обратно на сервер cookie.

Первый запрос очень прост:

1
2
HttpPost post = new HttpPost(url);
HttpResponse resp = client.execute(post);

Затем мы читаем печенье (строка 1,3):

01
02
03
04
05
06
07
08
09
10
CookieStore store = ((DefaultHttpClient) client).getCookieStore();
 
List<Cookie> cookies = store.getCookies();
if (cookies != null) {
    for (Cookie c : cookies) {
        System.out.println("Name ["+c.getName()+"] - Val ["+c.getValue()+"]
                      - Domain ["+c.getDomain()+"] - Path ["+c.getPath()+"]");
        store.addCookie(c);
    }
}

В строке 1 мы просто получаем магазин cookie, где хранятся файлы cookie. В строке 3 мы получаем список файлов cookie. Во втором пост-запросе мы должны сохранить cookie, который мы получили в первом запросе, поэтому имеем:

1
2
3
4
5
6
7
HttpContext ctx = new BasicHttpContext();
ctx.setAttribute(ClientContext.COOKIE_STORE, store);
 
// Post again with cookie
HttpPost post1 = new HttpPost(url);
client.execute(post1);
HttpResponse resp1 = client.execute(post, ctx);

В строке 1 мы создаем BasicHttpContext для обработки файлов cookie, а в строке 2 мы устанавливаем хранилище в нашем контексте и, наконец, в строке 7 мы выполняем запрос, передавая также контекст.

Следует заметить, что DefaultHttpClient всегда один и тот же, поэтому мы можем повторно использовать файлы cookie .

Запустив пример, который мы имеем:

android_http_apache_client_cookie android_http_apache_client_server_cookie
Вывод файлов cookie на стороне клиента Вывод cookie на стороне сервера

Исходный код доступен на GitHub .

Ссылка: Android Apache HTTP Client от нашего партнера JCG Франческо Аццола в блоге Surviving w / Android .