前言

  上一篇文章介绍了使用HttpURLConnection来完成对于HTTP协议的支持,现在介绍一个新的方式来访问Web站点,那就是HttpClient。

  HttpClient是Apache开源组织提供的一个开源的项目,从名字上就可以看出,它是一个简单的HTTP客户端(并不是浏览器),可以发送HTTP请求,接受HTTP响应。但是不会缓存服务器的响应,不能执行HTTP页面中签入嵌入的JS代码,自然也不会对页面内容进行任何解析、处理,这些都是需要开发人员来完成的。

  现在Android已经成功集成了HttpClient,所以开发人员在Android项目中可以直接使用HttpClient来想Web站点提交请求以及接受响应,如果使用其他的Java项目,需要引入进相应的Jar包。HttpClient可以在官网上下载

  

HttpClient

  HttpClient其实是一个interface类型,HttpClient封装了对象需要执行的Http请求、身份验证、连接管理和其它特性。从文档上看,HttpClient有三个已知的实现类分别是:AbstractHttpClient, AndroidHttpClient, DefaultHttpClient,会发现有一个专门为Android应用准备的实现类AndroidHttpClient,当然使用常规的DefaultHttpClient也可以实现功能,但是既然开发的是Android应用程序,还是使用Android专有的实现类,一定有其优势。

  从两个类包所有在位置就可以看出区别,AndroidHttpClient定义在android.net.http.AndroidHttpClient包下,属于Android原生的http访问,而DefaultHttpClient定义在org.apache.http.impl.client.DefaultHttpClient包下,属于对apche项目的支持。而AndroidHttpClient没有公开的构造函数,只能通过静态方法newInstance()方法来获得AndroidHttpClient对象。

  AndroidHttpClient对于DefaultHttpClient做了一些改进,使其更使用用于Android项目:

  1. 关掉过期检查,自连接可以打破所有的时间限制。
  2. 可以设置ConnectionTimeOut(连接超时)和SoTimeout(读取数据超时)。
  3. 关掉重定向。
  4. 使用一个Session缓冲用于SSL Sockets。
  5. 如果服务器支持,使用gzip压缩方式用于在服务端和客户端传递的数据。
  6. 默认情况下不保留Cookie。    

  简单来说,用HttpClient发送请求、接收响应都很简单,只需要几个步骤即可:

  1. 创建HttpClient对象。
  2. 创建对应的发送请求的对象,如果需要发送GET请求,则创建HttpGet对象,如果需要发送POST请求,则创建HttpPost对象。
  3. 对于发送请求的参数,GET和POST使用的方式不同,GET方式可以使用拼接字符串的方式,把参数拼接在URL结尾;POST方式需要使用setEntity(HttpEntity entity)方法来设置请求参数。
  4. 调用HttpClient对象的execute(HttpUriRequest request)发送请求,执行该方法返回一个HttpResponse对象。
  5. 调用HttpResponse的对应方法获取服务器的响应头、响应内容等。

DefaultHttpClient

  先看看使用DefaultHttpClient方式发送Web站点请求,上面已经简要说明了步骤,在这里简要说明一个参数的传递问题,对于GET方式,只需要拼接字符串就在URL结尾即可,但是对于POST方式,需要传递HttpEntity对象,HttpEntity为一个接口,有多个实现类,可以使用其间接子继承,UrlEncodedFormEntity类来保存请求参数,并传递给HttpPost。

  此例子简单实现了在Android客户端使用DefaultHttpClient实现一个Http站点登陆的实现,使用的是POST传递,其传递值只需要传递username+password即可,当传递的数据为admin+123则认为登陆成功。Web站点使用.net的架构,一个一般处理程序,简单的比对账户密码,这里就不在此讲解。

  因为Android4.0之后对使用网络有特殊要求,已经无法再在主线程中访问网络了,必须使用多线程访问的模式,其他的一些信息在代码注释中已经说明。

DefaultHttpClient-Code

  1 package com.bgxt.httpUtils;
2
3 import java.io.ByteArrayOutputStream;
4 import java.io.IOException;
5 import java.io.InputStream;
6 import java.io.UnsupportedEncodingException;
7 import java.util.ArrayList;
8 import java.util.HashMap;
9 import java.util.List;
10 import java.util.Map;
11
12 import org.apache.http.HttpResponse;
13 import org.apache.http.NameValuePair;
14 import org.apache.http.client.ClientProtocolException;
15 import org.apache.http.client.entity.UrlEncodedFormEntity;
16 import org.apache.http.client.methods.HttpPost;
17 import org.apache.http.impl.client.DefaultHttpClient;
18 import org.apache.http.message.BasicNameValuePair;
19
20 public class httpClientUtils implements Runnable {
21 /**
22 * 对于Android4.0之上的环境下,不能在主线程中访问网络 所以这里另新建了一个实现了Runnable接口的Http访问类
23 */
24 private String username;
25 private String password;
26
27 public httpClientUtils(String username, String password) {
28 // 初始化用户名和密码
29 this.username = username;
30 this.password = password;
31 }
32
33 @Override
34 public void run() {
35 // 设置访问的Web站点
36 String path = "http://192.168.1.103:1231/loginas.ashx";
37 // 设置Http请求参数
38 Map<String, String> params = new HashMap<String, String>();
39 params.put("username", username);
40 params.put("password", password);
41
42 String result = sendHttpClientPost(path, params, "utf-8");
43 // 把返回的接口输出
44 System.out.println(result);
45 }
46
47 /**
48 * 发送Http请求到Web站点
49 *
50 * @param path
51 * Web站点请求地址
52 * @param map
53 * Http请求参数
54 * @param encode
55 * 编码格式
56 * @return Web站点响应的字符串
57 */
58 private String sendHttpClientPost(String path, Map<String, String> map,
59 String encode) {
60 List<NameValuePair> list = new ArrayList<NameValuePair>();
61 if (map != null && !map.isEmpty()) {
62 for (Map.Entry<String, String> entry : map.entrySet()) {
63 // 解析Map传递的参数,使用一个键值对对象BasicNameValuePair保存。
64 list.add(new BasicNameValuePair(entry.getKey(), entry
65 .getValue()));
66 }
67 }
68 try {
69 // 实现将请求 的参数封装封装到HttpEntity中。
70 UrlEncodedFormEntity entity = new UrlEncodedFormEntity(list, encode);
71 // 使用HttpPost请求方式
72 HttpPost httpPost = new HttpPost(path);
73 // 设置请求参数到Form中。
74 httpPost.setEntity(entity);
75 // 实例化一个默认的Http客户端
76 DefaultHttpClient client = new DefaultHttpClient();
77 // 执行请求,并获得响应数据
78 HttpResponse httpResponse = client.execute(httpPost);
79 // 判断是否请求成功,为200时表示成功,其他均问有问题。
80 if (httpResponse.getStatusLine().getStatusCode() == 200) {
81 // 通过HttpEntity获得响应流
82 InputStream inputStream = httpResponse.getEntity().getContent();
83 return changeInputStream(inputStream, encode);
84 }
85 } catch (UnsupportedEncodingException e) {
86 e.printStackTrace();
87 } catch (ClientProtocolException e) {
88 e.printStackTrace();
89 } catch (IOException e) {
90 e.printStackTrace();
91 }
92 return "";
93 }
94
95 /**
96 * 把Web站点返回的响应流转换为字符串格式
97 *
98 * @param inputStream
99 * 响应流
100 * @param encode
101 * 编码格式
102 * @return 转换后的字符串
103 */
104 private String changeInputStream(InputStream inputStream, String encode) {
105 ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
106 byte[] data = new byte[1024];
107 int len = 0;
108 String result = "";
109 if (inputStream != null) {
110 try {
111 while ((len = inputStream.read(data)) != -1) {
112 outputStream.write(data, 0, len);
113 }
114 result = new String(outputStream.toByteArray(), encode);
115
116 } catch (IOException e) {
117 e.printStackTrace();
118 }
119 }
120 return result;
121 }
122
123 }

AndroidHttpClient

  使用AndroidHttpClient的方式和DefaultHttpClient差不多,不多的几点区别上面已经说明,但是在此例子中没有体现。有一点需要注意的是,AndroidHttpClient是一个final类,也没有公开的构造函数,所以无法使用new的形式对其进行实例化,必须使用AndroidHttpClient.newInstance()方法获得AndroidHttpClient对象。

  示例中依然是使用POST请求,实现的功能和DefaultHttpClient示例一样。细节部分已经在注释中体现,直接看代码即可。

  1 package com.bgxt.httpUtils;
2
3 import java.io.ByteArrayOutputStream;
4 import java.io.IOException;
5 import java.io.InputStream;
6 import java.io.UnsupportedEncodingException;
7 import java.util.ArrayList;
8 import java.util.HashMap;
9 import java.util.List;
10 import java.util.Map;
11
12 import org.apache.http.HttpResponse;
13 import org.apache.http.NameValuePair;
14 import org.apache.http.client.ClientProtocolException;
15 import org.apache.http.client.HttpClient;
16 import org.apache.http.client.entity.UrlEncodedFormEntity;
17 import org.apache.http.client.methods.HttpPost;
18 import org.apache.http.impl.client.DefaultHttpClient;
19 import org.apache.http.message.BasicNameValuePair;
20
21 import android.net.http.AndroidHttpClient;
22
23 public class AndroidHttpClientUtils implements Runnable {
24
25 private String username;
26 private String password;
27
28 public AndroidHttpClientUtils(String username, String password) {
29 // 初始化用户名和密码
30 this.username = username;
31 this.password = password;
32 }
33
34 @Override
35 public void run() {
36 // 设置访问的Web站点
37 String path = "http://192.168.1.103:1231/loginas.ashx";
38 //设置Http请求参数
39 Map<String, String> params = new HashMap<String, String>();
40 params.put("username", username);
41 params.put("password", password);
42
43 String result = sendHttpClientPost(path, params, "utf-8");
44 //把返回的接口输出
45 System.out.println(result);
46 }
47 /**
48 * 发送Http请求到Web站点
49 * @param path Web站点请求地址
50 * @param map Http请求参数
51 * @param encode 编码格式
52 * @return Web站点响应的字符串
53 */
54 private String sendHttpClientPost(String path,Map<String, String> map,String encode)
55 {
56 List<NameValuePair> list=new ArrayList<NameValuePair>();
57 if(map!=null&&!map.isEmpty())
58 {
59 for(Map.Entry<String, String> entry:map.entrySet())
60 {
61 //解析Map传递的参数,使用一个键值对对象BasicNameValuePair保存。
62 list.add(new BasicNameValuePair(entry.getKey(), entry.getValue()));
63 }
64 }
65 try {
66 //实现将请求 的参数封装封装到HttpEntity中。
67 UrlEncodedFormEntity entity=new UrlEncodedFormEntity(list, encode);
68 //使用HttpPost请求方式
69 HttpPost httpPost=new HttpPost(path);
70 //设置请求参数到Form中。
71 httpPost.setEntity(entity);
72 //实例化一个默认的Http客户端,使用的是AndroidHttpClient
73 HttpClient client=AndroidHttpClient.newInstance("");
74 //执行请求,并获得响应数据
75 HttpResponse httpResponse= client.execute(httpPost);
76 //判断是否请求成功,为200时表示成功,其他均问有问题。
77 if(httpResponse.getStatusLine().getStatusCode()==200)
78 {
79 //通过HttpEntity获得响应流
80 InputStream inputStream=httpResponse.getEntity().getContent();
81 return changeInputStream(inputStream,encode);
82 }
83
84 } catch (UnsupportedEncodingException e) {
85 // TODO Auto-generated catch block
86 e.printStackTrace();
87 } catch (ClientProtocolException e) {
88 // TODO Auto-generated catch block
89 e.printStackTrace();
90 } catch (IOException e) {
91 // TODO Auto-generated catch block
92 e.printStackTrace();
93 }
94
95 return "";
96 }
97 /**
98 * 把Web站点返回的响应流转换为字符串格式
99 * @param inputStream 响应流
100 * @param encode 编码格式
101 * @return 转换后的字符串
102 */
103 private String changeInputStream(InputStream inputStream,
104 String encode) {
105 ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
106 byte[] data = new byte[1024];
107 int len = 0;
108 String result="";
109 if (inputStream != null) {
110 try {
111 while ((len = inputStream.read(data)) != -1) {
112 outputStream.write(data,0,len);
113 }
114 result=new String(outputStream.toByteArray(),encode);
115
116 } catch (IOException e) {
117 e.printStackTrace();
118 }
119 }
120 return result;
121 }
122 }

  在本文的示例中,环境是使用的Android项目,可以对其进行简单的界面布局,如图:

  如果输入用户和密码为:admin+123,则可以再LogCat中查看到登录成功。

  源码下载

总结

  最近的两次博客中,已经分别介绍了HttpUrlConnection和HttpClient两种方式,通过Http协议对Web站点的访问。如果还不了解HttpURLConnection的读者,可以看看Android--Http协议

  根据官方文档上说的显示,Android包括两个Http客户端:HttpURLConnection和Apache HttpClient。并且都支持HTTPS,流媒体上传下载,并且可配置超时以及支持IPv6和连接池技术。但是因为移动设备的局限性,HttpURLConnection会是比Apache Http更好的选择,因为其API简单,运行消耗内存小,并且具有公开化的压缩算法,以及响应缓存,能更好的减少网络使用,提供运行速度和节省电池。

  但是也不能否认Apache HttpClient,它有大量的灵活的API,实现比较稳定,少有Bug,可造成的问题就是很难在不影响其兼容性的情况下对其进行改进了。现在Android开发者已经慢慢放弃Apache HttpClient的使用,转而使用HttpURLConnection。但是对于Android2.2之前的版本,HttpURLConnection具有一个致命的BUG,在响应输入流InputStream中调用.Close()方法将会阻碍连接池,因为这个BUG,只能放弃连接池的使用,但是Apache HttpClient不存在这个问题,当然Android2.3之后的版本中,HttpURLConnection已经解决了这个BUG,可以放心使用。

Android--Apache HttpClient(2种实现)的更多相关文章

  1. 在android 6.0(API 23)中,Google已经移除了移除了Apache HttpClient相关的类

    推荐使用HttpUrlConnection,如果要继续使用需要Apache HttpClient,需要在eclipse下libs里添加org.apache.http.legacy.jar,androi ...

  2. Android 6.0删除Apache HttpClient相关类的解决方法

    相应的官方文档如下: 上面文档的大致意思是,在Android 6.0(API 23)中,Google已经移除了Apache HttpClient相关的类,推荐使用HttpUrlConnection. ...

  3. android 中对apache httpclient及httpurlconnection的选择

    在官方blog中,android工程师谈到了如何去选择apache client和httpurlconnection的问题: 原文见http://android-developers.blogspot ...

  4. Android 数据存储五种方式

    1.概述 Android提供了5种方式来让用户保存持久化应用程序数据.根据自己的需求来做选择,比如数据是否是应用程序私有的,是否能被其他程序访问,需要多少数据存储空间等,分别是: ① 使用Shared ...

  5. Android使用HttpClient请求服务器代码优化版

    首先,我在前面的两篇博文中介绍了在Android中,除了使用java.net包下HttpUrlConnection的API访问HTTP服务之外,我们还可以换一种途径去完成工作.Android SDK附 ...

  6. Android系统的五种数据存储形式(二)

    之前介绍了Android系统下三种数据存储形式,今天补充介绍另外两种,分别是内容提供者和网络存储.有些人可能认为内存提供者和网络存储更偏向于对数据的操作而不是数据的存储,但这两种方式确实与数据有关,所 ...

  7. 使用搜狐Sendcloud的Webapi发送邮件:Jodd和Apache Httpclient

    最近,在使用搜狐Sendcloud发邮件.    Sendcloud提供http格式的webapi,方便地发送邮件,当然是要付费的. 很早之前,http工具一直用Httpclient,后来觉得jodd ...

  8. 如何在Apache HttpClient中设置TLS版本

    1.简介 Apache HttpClient是一个底层.轻量级的客户端HTTP库,用于与HTTP服务器进行通信. 在本教程中,我们将学习如何在使用HttpClient时配置支持的传输层安全(TLS)版 ...

  9. Apache HttpClient 5 使用详细教程

    点赞再看,动力无限. 微信搜「程序猿阿朗 」. 本文 Github.com/niumoo/JavaNotes 和 未读代码博客 已经收录,有很多知识点和系列文章. 超文本传输协议(HTTP)可能是当今 ...

  10. Android系统的五种数据存储形式(一)

    Android系统有五种数据存储形式,分别是文件存储.SP存储.数据库存储.contentprovider 内容提供者.网络存储.其中,前四个是本地存储.存储的类型包括简单文本.窗口状态存储.音频视频 ...

随机推荐

  1. 使用 OpCache 提升 PHP 性能

    使用 OpCache 提升 PHP 性能 wdd2007wdd2007 .6k 1月29日 发布 推荐 推荐 收藏 收藏,.3k 浏览 OpCache 通过对 opcode 的缓存和优化来提升 PHP ...

  2. layui中当悬浮在select的option上面是给不同的提示;

    $(document).on('mouseenter', '#paramsFather .layui-form-selected dl dd', function () { var data = $( ...

  3. unittest最详细的解说

    转自:http://www.imooc.com/article/257230 一.什么是unittest unittest是Python单元测试框架,类似于JUnit框架. unittest中有4个重 ...

  4. 【持续更新】总结:C++开发时积累的一些零碎的东西

    Makefile template update: 1.调整了顺序,把经常编辑的部分集中在了Makefile的下半部分 2.进行了一些重构实现更多的代码复用,见红色高亮部分,LIBPATH_ALL和L ...

  5. Archive for required library xx cannot be read or is not a valid ZIP file

    原因:maven下载的jar包有问题,导致maven编译的时候出错 解决方法:找到jar包所在的文件路径,在网上重新下载个相同版本的jar包,问题解决

  6. linux学习笔记8--命令touch

    linux的touch命令不常用,一般在使用make的时候可能会用到,用来修改文件时间戳,或者新建一个不存在的文件. touch命令有两个功能:一是用于把已存在文件的时间标签更新为系统当前的时间(默认 ...

  7. 获取真实的IE版本(转)

    IE 的浏览器模式和文本模式(二) 发表于 2013-09-07 Author: Jerry Qu 文章目录 判断真正的 IE 版本 JScript 引擎版本号 文本模式对 JScript 没影响? ...

  8. 恶习为什么难戒?因为你在HALT状态

          幸福课 | 恶习为什么难戒?因为你在HALT状态 文 游识猷 饥饿(hungry).生气(angry).孤单(lonely).疲惫(tired)这4种状态,被称为HALT——这个词刚好是英 ...

  9. bcrypt install `node-pre-gyp install --fallback-to-build`

    npm安装parse-server的过程中遇到了2次错误 尝试1 ganiks@ganiks-ubuntu-trusty-64:~$ sudo npm i -g parse-server npm WA ...

  10. ssd算法论文理解

    这篇博客主要是讲下我在阅读ssd论文时对论文的理解,并且自行使用pytorch实现了下论文的内容,并测试可以用. 开篇放下论文地址https://arxiv.org/abs/1512.02325,可以 ...