转载: http://liuwangshu.cn/application/network/2-httpclienthttp-urlconnection.html
1.HttpClient
Android SDK中包含了HttpClient,在Android6.0版本直接删除了HttpClient类库,如果仍想使用则解决方法是:
- 如果使用的是eclipse则在libs中加入org.apache.http.legacy.jar
这个jar包在:**sdk\platforms\android-23\optional目录中(需要下载android
6.0的SDK) - 如果使用的是android studio则 在相应的module下的build.gradle中加入:
android {
useLibrary
'org.apache.http.legacy'
+
}
+
|
HttpClient的GET请求
首先我们来用DefaultHttpClient类来实例化一个HttpClient,并配置好默认的请求参数:
//创建HttpClient
private HttpClient createHttpClient() {
HttpParams mDefaultHttpParams =
new BasicHttpParams();
+
//设置连接超时
HttpConnectionParams.setConnectionTimeout(mDefaultHttpParams,
15000);
+
//设置请求超时
HttpConnectionParams.setSoTimeout(mDefaultHttpParams,
15000);
+
HttpConnectionParams.setTcpNoDelay(mDefaultHttpParams,
true);
+
HttpProtocolParams.setVersion(mDefaultHttpParams, HttpVersion.HTTP_1_1);
+
HttpProtocolParams.setContentCharset(mDefaultHttpParams, HTTP.UTF_8);
+
//持续握手
HttpProtocolParams.setUseExpectContinue(mDefaultHttpParams,
true);
+
HttpClient mHttpClient =
new DefaultHttpClient(mDefaultHttpParams);
+
return mHttpClient;
}
+
|
接下来创建HttpGet和HttpClient,请求网络并得到HttpResponse,并对HttpResponse进行处理:
private void useHttpClientGet(String url) {
HttpGet mHttpGet =
new HttpGet(url);
+
mHttpGet.addHeader(
"Connection",
"Keep-Alive");
+
try {
HttpClient mHttpClient = createHttpClient();
+
HttpResponse mHttpResponse = mHttpClient.execute(mHttpGet);
+
HttpEntity mHttpEntity = mHttpResponse.getEntity();
+
int code = mHttpResponse.getStatusLine().getStatusCode();
if (
null != mHttpEntity) {
InputStream mInputStream = mHttpEntity.getContent();
+
String respose = converStreamToString(mInputStream);
+
Log.i(
"wangshu",
"请求状态码:" + code +
"\n请求结果:\n" + respose);
+
mInputStream.close();
+
}
+
}
catch (IOException e) {
+
e.printStackTrace();
+
}
+
}
|
converStreamToString方法将请求结果转换成String类型:
private String converStreamToString(InputStream is) throws IOException {
BufferedReader reader =
new BufferedReader(
new InputStreamReader(is));
+
StringBuffer sb =
new StringBuffer();
+
String line =
null;
+
while ((line = reader.readLine()) !=
null) {
sb.append(line +
"\n");
+
}
+
String respose = sb.toString();
+
return respose;
}
+
|
最后我们开启线程访问百度:
new Thread(
new Runnable() {
public void run() {
useHttpClientGet(
"http://www.baidu.com");
+
}
+
}).start();
+
|
请求的返回结果,请求状态码为200,结果就是个html页,这里只截取了部分html代码:
GET请求的参数暴露在URL中,这有些不大妥当,而且URL的长度也有限制:长度在2048字符之内,在HTTP 1.1后URL长度才没有限制。一般情况下POST可以替代GET,接下来我们来看看HttpClient的POST请求。
HttpClient的POST请求
post请求和get类似就是需要配置要传递的参数:
private void useHttpClientPost(String url) {
+
HttpPost mHttpPost = new HttpPost(url);
+
mHttpPost.addHeader("Connection", "Keep-Alive");
+
try {
+
HttpClient mHttpClient = createHttpClient();
+
List<NameValuePair> postParams = new ArrayList<>();
+
//要传递的参数
+
postParams.add(new BasicNameValuePair("username", "moon"));
+
postParams.add(new BasicNameValuePair("password", "123"));
+
mHttpPost.setEntity(new UrlEncodedFormEntity(postParams));
+
HttpResponse mHttpResponse = mHttpClient.execute(mHttpPost);
+
HttpEntity mHttpEntity = mHttpResponse.getEntity();
+
int code = mHttpResponse.getStatusLine().getStatusCode();
+
if (null != mHttpEntity) {
+
InputStream mInputStream = mHttpEntity.getContent();
+
String respose = converStreamToString(mInputStream);
+
Log.i("wangshu", "请求状态码:" + code + "\n请求结果:\n" + respose);
+
mInputStream.close();
+
}
+
} catch (IOException e) {
+
e.printStackTrace();
+
}
+
}
|
2.HttpURLConnection
Android 2.2版本之前,HttpURLConnection一直存在着一些令人厌烦的bug。比如说对一个可读的InputStream调用close()方法时,就有可能会导致连接池失效了。那么我们通常的解决办法就是直接禁用掉连接池的功能:
private void disableConnectionReuseIfNecessary() {
+
// 这是一个2.2版本之前的bug
+
if (Integer.parseInt(Build.VERSION.SDK) < Build.VERSION_CODES.FROYO) {
+
System.setProperty("http.keepAlive", "false");
+
}
+
}
|
所以在Android 2.2版本以及之前的版本使用HttpClient是较好的选择,而在Android 2.3版本及以后,HttpURLConnection则是最佳的选择,它的API简单,体积较小,因而非常适用于Android项目。压缩和缓存机制可以有效地减少网络访问的流量,在提升速度和省电方面也起到了较大的作用。另外在Android 6.0版本中,HttpClient库被移除了,HttpURLConnection则是以后我们唯一的选择。+
HttpURLConnection的POST请求
因为会了HttpURLConnection的POST请求那GET请求也就会了,所以我这里只举出POST的例子
首先我们创建一个UrlConnManager类,然后里面提供getHttpURLConnection()方法用于配置默认的参数并返回HttpURLConnection:
public static HttpURLConnection getHttpURLConnection(String url){
HttpURLConnection mHttpURLConnection=
null;
+
try {
URL mUrl=
new URL(url);
+
mHttpURLConnection=(HttpURLConnection)mUrl.openConnection();
+
//设置链接超时时间
mHttpURLConnection.setConnectTimeout(
15000);
+
//设置读取超时时间
mHttpURLConnection.setReadTimeout(
15000);
+
//设置请求参数
mHttpURLConnection.setRequestMethod(
"POST");
+
//添加Header
mHttpURLConnection.setRequestProperty(
"Connection",
"Keep-Alive");
+
//接收输入流
mHttpURLConnection.setDoInput(
true);
+
//传递参数时需要开启
mHttpURLConnection.setDoOutput(
true);
+
}
catch (IOException e) {
+
e.printStackTrace();
+
}
+
return mHttpURLConnection ;
}
|
因为我们要发送POST请求,所以在UrlConnManager类中再写一个postParams()方法用来组织一下请求参数并将请求参数写入到输出流中:
public static void postParams(OutputStream output,List<NameValuePair>paramsList) throws IOException{
StringBuilder mStringBuilder=
new StringBuilder();
+
for (NameValuePair pair:paramsList){
if(!TextUtils.isEmpty(mStringBuilder)){
mStringBuilder.append(
"&");
+
}
+
mStringBuilder.append(URLEncoder.encode(pair.getName(),
"UTF-8"));
+
mStringBuilder.append(
"=");
+
mStringBuilder.append(URLEncoder.encode(pair.getValue(),
"UTF-8"));
+
}
+
BufferedWriter writer=
new BufferedWriter(
new OutputStreamWriter(output,
"UTF-8"));
+
writer.write(mStringBuilder.toString());
+
writer.flush();
+
writer.close();
+
}
|
接下来我们添加请求参数,调用postParams()方法将请求的参数组织好传给HttpURLConnection的输出流,请求连接并处理返回的结果:
private void useHttpUrlConnectionPost(String url) {
InputStream mInputStream =
null;
+
HttpURLConnection mHttpURLConnection = UrlConnManager.getHttpURLConnection(url);
+
try {
List<NameValuePair> postParams =
new ArrayList<>();
+
//要传递的参数
postParams.add(
new BasicNameValuePair(
"username",
"moon"));
+
postParams.add(
new BasicNameValuePair(
"password",
"123"));
+
UrlConnManager.postParams(mHttpURLConnection.getOutputStream(), postParams);
+
mHttpURLConnection.connect();
+
mInputStream = mHttpURLConnection.getInputStream();
+
int code = mHttpURLConnection.getResponseCode();
String respose = converStreamToString(mInputStream);
+
Log.i(
"wangshu",
"请求状态码:" + code +
"\n请求结果:\n" + respose);
+
mInputStream.close();
+
}
catch (IOException e) {
+
e.printStackTrace();
+
}
+
}
|
最后开启线程请求网络:
private void useHttpUrlConnectionGetThread() {
new Thread(
new Runnable() {
public void run() {
useHttpUrlConnectionPost(
"http://www.baidu.com");
+
}
+
}).start();
+
}
+
|
mInputStream = mHttpURLConnection.getInputStream() 这句代码报错了,找不到文件。打开Fiddler来分析一下,不了解Fiddler和HTTP协议原理的请查看Android网络编程(一)HTTP协议原理这篇文章。+
看来请求报文没有问题,再来看看响应报文:
报504错误,读取响应的数据报错,对于我们这次请求服务端不能返回完整的响应,返回的数据为0 bytes,所以mHttpURLConnection.getInputStream() 也读不到服务端响应的输入流。当然这次错误是正常的,百度没理由处理我们的这次POST请求。