В этом посте я хочу описать, как создать 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 . Запустив пример, который мы имеем:
Серверная сторона |
Скачать двоичные данные
Еще одна распространенная операция — загрузка двоичных данных с сервера. В этом случае мы хотим загрузить изображение с сервера и показать его в нашем пользовательском интерфейсе.
Операция очень проста, потому что в этом случае мы должны сделать запрос 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); |
Запустив приложение мы имеем:
Серверная сторона |
Обмен куки
Одним интересным аспектом протокола 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 .
Запустив пример, который мы имеем:
Вывод файлов cookie на стороне клиента | Вывод cookie на стороне сервера |
Исходный код доступен на GitHub .