一、简介
HttpClient
是Apache
开源组织提供的HTTP
网络访问接口,它是一个简单的HTTP
客户端(并不是浏览器),可以发送HTTP
请求,接收HTTP
响应,但是不会缓存服务器的响应,不能执行HTTP
页面中嵌入的JS
代码,自然也不会对页面内容进行任何解析、处理,这些都是需要开发人员来完成的。
现在Android
已经成功集成了HttpClient
,所以开发人员在Android
项目中可以直接使用HttpClient
来向Web
站点提交请求以及接受响应,如果使用其他的Java
项目则需要引入相应的Jar
包。HttpClient
可以在官网上下载,官网链接:http://hc.apache.org/downloads.cgi
HttpClient
其实是一个interface
类型,它封装了对象需要执行的HTTP
请求、身份验证、连接管理和其它特性。由于HttpClient
是一个接口,因此无法创建它的实例,但是HttpClient
有三个已知的实现类分别是:AbstractHttpClient
、AndroidHttpClient
、DefaultHttpClient
,会发现有一个专门为Android
应用准备的实现类AndroidHttpClient
,当然使用常规的DefaultHttpClient
也可以实现功能。
从两个类包所在位置就可以看出区别:AndroidHttpClient
定义在android.net.http.AndroidHttpClient
包下,属于Android
原生的HTTP
访问;而DefaultHttpClient
定义在org.apache.http.impl.client.DefaultHttpClient
包下,属于对Apache
项目的支持。而AndroidHttpClient
没有公开的构造函数,只能通过静态方法newInstance()
方法来获得AndroidHttpClient
对象。
二、特性
- 基于标准、纯净的
Java
语言,实现了Http1.0
和Http1.1
; - 以可扩展的面向对象结构实现了
HTTP
全部的方法(GET
、POST
、PUT
、DELETE
、HEAD
、OPTIONS
、TRACE
); - 支持
HTTPS
协议; - 通过
HTTP
代理建立透明的连接; - 利用
CONNECT
方法通过HTTP
代理建立隧道的HTTPS
连接; Basic
、Digest
、NTLMv1
、NTLMv2
、NTLM2 Session
、SNPNEGO/Kerberos
认证方案;- 插件式的自定义认证方案;
- 便携可靠的套接字工厂使它更容易的使用第三方解决方案;
- 连接管理器支持多线程应用,支持设置最大连接数,同时支持设置每个主机的最大连接数,发现并关闭过期的连接;
- 自动处理
Set-Cookie
中的Cookie
; - 插件式的自定义
Cookie
策略; Request
的输出流可以避免流中内容直接缓冲到Socket
服务器;Response
的输入流可以有效的从Socket
服务器直接读取相应内容;- 在
Http1.0
和Http1.1
中利用KeepAlive
保持持久连接; - 直接获取服务器发送的
response code
和headers
; - 设置连接超时的能力;
- 实验性的支持
http1.1 response caching
; - 源代码基于
Apache License
可免费获取;
三、集成
在Eclipse
或Android Studio
开发过程中,设置Android SDK
的编译版本为23
且使用了HttpClient
相关类的方法时会出现有一些类找不到的错误。
原因
Android 6.0(API 23)SDK
不再提供org.apache.http.*
(只保留几个类)。解决方法
2.1Eclipse
:在项目libs
中加入:org.apache.http.legacy.jar
上面的jar
包在:**\android-sdk-windows\platforms\android-23\optional
下(需要下载Android 6.0
的SDK
)。2.2
Android Studio
:在项目相应module
的build.gradle
中加入:android { useLibrary 'org.apache.http.legacy' }
四、权限
在AndroidManifest.xml
文件添加网络权限
<uses-permission android:name="android.permission.INTERNET" />
五、混淆
#不混淆android-async-http(这里混淆由你使用的HttpClient框架决定)
-keep class com.loopj.android.http.**{*;}
#不混淆org.apache.http.legacy.jar
-dontwarn android.net.compatibility.**
-dontwarn android.net.http.**
-dontwarn com.android.internal.http.multipart.**
-dontwarn org.apache.commons.**
-dontwarn org.apache.http.**
-keep class android.net.compatibility.**{*;}
-keep class android.net.http.**{*;}
-keep class com.android.internal.http.multipart.**{*;}
-keep class org.apache.commons.**{*;}
-keep class org.apache.http.**{*;}
六、使用
简单来说,使用HttpClient
发送请求、接收响应都很简单,只需要五大步骤即可:
- 创建客户端的
HttpClient
对象; - 创建请求的对象。如果需要发送
GET
请求,则创建HttpGet
对象;如果需要发送POST
请求,则创建HttpPost
对象。注:对于发送请求的参数而言GET
和POST
的使用方式略有不同,GET
方式可以使用拼接字符串的方式将参数拼接在URL
末尾;POST
方式则需要使用setEntityHttpEntity entity)
方法来设置请求参数; - 调用
HttpClient
对象的execute(HttpUriRequest request)
发送请求,执行该方法后将获得服务器返回的HttpResponse
对象。服务器返回给我们的数据就在这个HttpResponse
相应当中,调用HttpResponse
的对应方法可以获取服务器的响应头、响应内容等; - 检查响应状态是否正常。服务器返回给客户端的响应有一个响应码:相应码为
200
时表示正常返回;相应码为404
时表示客户端错误;相应码为505
时表示服务器端错误; - 获得响应对象当中的数据。
七、调用
主线程中访问网络时异常:NetworkOnMainThreadException
- 原因
Android
在4.0
之前的版本支持在主线程中访问网络,但是在4.0
以后对这部分程序进行了优化,也就是说访问网络的代码不能写在主线程中了。 - 解决方法
采用多线程、异步加载的方式加载数据。
八、示例
public static final int CONNECTION_TIME_OUT = 1000 * 20;//连接超时
public static final int SO_TIMEOUT = 1000 * 20;//Socket 超时
public static final String ENCODING = "UTF-8";//编码格式
/**
* HttpClient Post 请求
*
* @param apiUrl 接口地址
* @param paramsMap 接口参数
* @return
*/
public static ResultDesc postRequest(String apiUrl, Map<String, String> paramsMap) {
// 创建表单
List<NameValuePair> params = new ArrayList<NameValuePair>();
if (paramsMap != null && paramsMap.size() != 0) {
for (String key : paramsMap.keySet()) {
params.add(new BasicNameValuePair(key, paramsMap.get(key)));
}
}
//创建HttpClient对象
HttpClient httpClient = getHttpClient();
//创建请求对象,参数是访问的服务器地址
HttpPost httpPost = new HttpPost(apiUrl);
HttpResponse httpResponse;
ResultDesc resultDesc = null;
try {
UrlEncodedFormEntity encode = new UrlEncodedFormEntity(params, ENCODING);
httpPost.setEntity(encode);
//执行请求,获取服务器返回的相应对象
httpResponse = httpClient.execute(httpPost);
//检查相应的状态是否正常,状态码返回值为200表示正常
if (httpResponse.getStatusLine().getStatusCode() == HttpStatus.SC_OK) {
//从相应对象当中取出数据放到entity当中
HttpEntity entity = httpResponse.getEntity();
//将entity当中的数据转换为字符串
String response = EntityUtils.toString(entity, ENCODING);
LogUtil.e(Constant.LOG_TAG, "接口地址:" + apiUrl + "\n请求返回:" + response);
resultDesc = getReturnData(response);
} else {
resultDesc = dataRestructuring(-1, UIUtils.getString(R.string.back_abnormal_results), "");
}
} catch (Exception e) {
resultDesc = dataRestructuring(-1, ExceptionCode(e), "");
}
return resultDesc;
}
/**
* HttpClient Get 请求
*
* @param apiUrl 接口地址
* @param paramsMap 接口参数
* @return
*/
public static ResultDesc getRequest(String apiUrl, Map<String, String> paramsMap) {
//创建表单
List<NameValuePair> params = new ArrayList<NameValuePair>();
if (paramsMap != null && paramsMap.size() != 0) {
for (String key : paramsMap.keySet()) {
params.add(new BasicNameValuePair(key, paramsMap.get(key)));
}
//对参数编码
String param = URLEncodedUtils.format(params, ENCODING);
apiUrl += "?" + param;
}
//创建HttpClient对象
HttpClient httpClient = getHttpClient();
//创建请求对象,参数是访问的服务器地址
HttpGet httpGet = new HttpGet(apiUrl);
HttpResponse httpResponse;
ResultDesc resultDesc = null;
try {
//执行请求,获取服务器返回的相应对象
httpResponse = httpClient.execute(httpGet);
//检查相应的状态是否正常,状态码返回值为200表示正常
if (httpResponse.getStatusLine().getStatusCode() == HttpStatus.SC_OK) {
//从相应对象当中取出数据放到entity当中
HttpEntity entity = httpResponse.getEntity();
//将entity当中的数据转换为字符串
String response = EntityUtils.toString(entity, ENCODING);
LogUtil.e(Constant.LOG_TAG, "接口地址:" + apiUrl + "\n请求返回:" + response);
resultDesc = getReturnData(response);
} else {
resultDesc = dataRestructuring(-1, UIUtils.getString(R.string.back_abnormal_results), "");
}
} catch (Exception e) {
resultDesc = dataRestructuring(-1, ExceptionCode(e), "");
}
return resultDesc;
}
/**
* HttpClient 配置
*
* @return
*/
public static HttpClient getHttpClient() {
//创建HttpParams以用来设置HTTP参数(这一部分不是必需的)
BasicHttpParams httpParams = new BasicHttpParams();
//设置连接超时
HttpConnectionParams.setConnectionTimeout(httpParams, CONNECTION_TIME_OUT);
//设置Socket超时
HttpConnectionParams.setSoTimeout(httpParams, SO_TIMEOUT);
//设置Socket缓存大小
HttpConnectionParams.setSocketBufferSize(httpParams, 8192);
//设置userAgent
String userAgent = "Mozilla/5.0 (Windows; U; Windows NT 5.1; zh-CN; rv:1.9.2) Gecko/20100115 Firefox/3.6";
HttpProtocolParams.setUserAgent(httpParams, userAgent);
//设置重定向,缺省为true
//HttpClientParams.setRedirecting(httpParams, true);
//设置HttpClient支持HTTP和HTTPS两种模式
//SchemeRegistry schReg = new SchemeRegistry();
//schReg.register(new Scheme("http", PlainSocketFactory.getSocketFactory(), 80));
//schReg.register(new Scheme("https", SSLSocketFactory.getSocketFactory(), 443));
//使用线程安全的连接管理来创建HttpClient
//ClientConnectionManager conMgr = new ThreadSafeClientConnManager(httpParams, schReg);
//创建HttpClient对象
//HttpClient httpClient = new DefaultHttpClient(conMgr, httpParams);
//创建HttpClient对象
HttpClient httpClient = new DefaultHttpClient(httpParams);
return httpClient;
}
项目地址 ☞ 传送门