Android网络编程(二)HttpClient与HttpURLConnection



转载:  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() {
@Override
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() {
@Override
public void run() {
useHttpUrlConnectionPost( "http://www.baidu.com"); +
} +
}).start(); +
} +

这里我们仍旧请求百度,看看会发生什么?
这里写图片描述

mInputStream = mHttpURLConnection.getInputStream() 这句代码报错了,找不到文件。打开Fiddler来分析一下,不了解Fiddler和HTTP协议原理的请查看Android网络编程(一)HTTP协议原理这篇文章。+

我们的请求报文:
这里写图片描述

看来请求报文没有问题,再来看看响应报文:

这里写图片描述

报504错误,读取响应的数据报错,对于我们这次请求服务端不能返回完整的响应,返回的数据为0 bytes,所以mHttpURLConnection.getInputStream() 也读不到服务端响应的输入流。当然这次错误是正常的,百度没理由处理我们的这次POST请求。

猜你喜欢

转载自blog.csdn.net/zzr1114969538/article/details/76456715