HttpClient与HttpURLConnection的区别(理论与实践结合)
来源:互联网 发布:评论盖楼的数据库设计 编辑:程序博客网 时间:2024/06/06 11:42
最新发布的android 6.0将Apache的HttpClient删除掉了,为了适应这一变化,有下面两种解决方法
编译时加入HttpClient的依赖以继续使用HttpClient
可参考我翻译的这篇文章android 6.0开发时的行为改变
抛弃HttpClient,全面使用HttpURLConnection
在决定使用哪种Http API之前,充分了解它们之间的差别很有必要。
我使用了理论与实践相结合的方式来对比了一下两者的区别。
理论
国内外关于两者对比的文章很多,但是我觉得最好的还是android官方出的一篇文章 - Android’s HTTP Clients,作者是Dalvik团队的Jesse Wilson,发表于2011年9月29日。
在这里,我简要地把这篇文章的关键点列一下。
以下内容主要是我的翻译。
两者主要都支持HTTPS,数据流的上传与下载,可设置的超时,IPv6和连接池。
HttpClient
DefaultHttpClient
和AndroidHttpClient
都是可扩展的HTTP客户端,适合web浏览器使用。它们的实现稳定并且bug较少。
但是大量的API使得android团队在不打破兼容性的前提下来改进它。所以android团队已经不再维护了。
HttpURLConnection
HttpURLConnection
是通用的、轻量的HTTP客户端,它适合大部分应用程序。这个类的起点很低,但是它的专注的API使得可以比较容易地稳步改进它。
在2.2版本之前,HttpURLConnection有一些基础性的bug。尤其是当在一个可读的InputStream上调用close()
方法时,会破坏连接池。通过禁用连接池可以解决这个问题:
private void disableConnectionReuseIfNecessary() { // HTTP connection reuse which was buggy pre-froyo if (Integer.parseInt(Build.VERSION.SDK) < Build.VERSION_CODES.FROYO) { System.setProperty("http.keepAlive", "false"); }}
从2.3版本开始,android团队加入了透明的响应压缩。HttpURLConnection会自动地将下面的Header加入到发出去的请求中:
Accept-Encoding: gzip
接下来的内容是一些具体的细节,这里就不翻译了,有兴趣的可以查看原文。
哪个更好
HttpClient在<=2.2的版本里bug较少,对这些版本它是最好的选择。
对于>=2.3的版本,HttpURLConnection无疑是最好的选择。它的API简单并且小巧使得它非常适合android。透明压缩和响应缓存降低了网络流量的使用,提升了速度并且节电。新应用应该使用HttpURLConnection;android团队也会全力开发改进这个API。
实践
我分别使用HttpClient和HttpClientConnection实现了同样的功能,通过代码可以理解上面说的为什么HttpClientConnection简单小巧。
代码部分
下面附上我的代码
HttpClient版本
private String getSpecifiedPageViaHttpClient(String url) { HttpClient client = null; InputStream inputStream = null; try { client = new DefaultHttpClient(); // 设置参数 HttpParams params = client.getParams(); params.setParameter(CoreConnectionPNames.CONNECTION_TIMEOUT, 3000); params.setParameter(CoreConnectionPNames.SO_TIMEOUT, 2000); // 构建请求 HttpGet httpGet = new HttpGet(url); httpGet.addHeader("Accept-Encoding", "gzip"); // 客户端可以处理gzip格式的数据 // 发送请求并获取响应 HttpResponse httpResponse = client.execute(httpGet); int statusCode = httpResponse.getStatusLine().getStatusCode(); if (statusCode == HttpStatus.SC_OK) { HttpEntity entity = httpResponse.getEntity(); if (entity != null) { // 是否经过gzip压缩 Header header = entity.getContentEncoding(); if (header != null && header.getValue().equalsIgnoreCase("gzip")) { inputStream = new GZIPInputStream(entity.getContent()); } else { inputStream = entity.getContent(); } return IOHelper.inputStream2String(inputStream); } } else { return "请求失败," + statusCode; } } catch (IOException e) { e.printStackTrace(); } finally { if (inputStream != null) { try { inputStream.close(); Log.d(null, "inputstream has been closed"); } catch (IOException e) { e.printStackTrace(); } } if (client != null) { client.getConnectionManager().shutdown(); // 直接关闭connection以释放服务器端的连接 } } return "未知错误"; }
HttpURLConnection版本
private String getSpecifiedPageViaHurl(String url) { HttpURLConnection urlConnection = null; InputStream inputStream = null; try { urlConnection = (HttpURLConnection) new URL(url).openConnection(); urlConnection.setConnectTimeout(3000); urlConnection.setReadTimeout(2000); urlConnection.setRequestMethod("GET"); urlConnection.connect(); int responseCode = urlConnection.getResponseCode(); if (responseCode == HttpURLConnection.HTTP_OK) { // HURL会自动透明地加入gzip的支持 inputStream = urlConnection.getInputStream(); return IOHelper.inputStream2String(inputStream); } else { return "请求失败," + responseCode; } } catch (IOException e) { e.printStackTrace(); } finally { if (inputStream != null) { try { inputStream.close(); } catch (IOException e) { e.printStackTrace(); } } if (urlConnection != null) { urlConnection.disconnect(); } } return "未知错误"; }
上面两个方法都用到的方法IOHelper.inputStream2String()
/** * 从输入流中读取数据到String对象中。<br/> * 注意:使用完InputStream请显式关闭。 * * @param is InputStream对象。 * @return 输入流的数据 */ public static String inputStream2String(InputStream is) { String data = null; ByteArrayOutputStream os = new ByteArrayOutputStream(); byte[] buf = new byte[1024]; int byteRead; try { while ((ByteRead = is.read(buf, 0, buf.length)) != -1) { os.write(buf, 0, byteRead); } } catch (IOException e) { System.out.println(e.getMessage()); } finally { try { data = os.toString("UTF-8"); } catch (UnsupportedEncodingException e1) { e1.printStackTrace(); } try { os.close(); } catch (IOException e) { System.out.println(e.getMessage()); } } return data; }
分析部分
首先先来看HttpClient版本的代码,为了实现功能,它引入了一系列的API
- 实际的HttpClient实现:DefaultHttpClient/AndroidHttpClient
- 设置参数:HttpParams
- 参数名:CoreConnectionPNames的常量
- 请求:HttpGet/HttpPost/…,请求header也在这些类里边配置
- 响应:HttpResponse
- 响应码:HttpStatusLine.getStatusCode()
- 响应码常量:HttpStatus
- header:Header
- 响应的数据流(InputStream):HttpEntity.getContent()
- 关闭Connection:ClientConnectionManager.shutdown()
上面的这些还只是比较基本的使用场景,如果要发送post请求或者使用proxy,则代码会更加复杂(引入的API会更多)。另外,gzip压缩也要手动处理。正如上面所说的,HttpClient适合web浏览器,因为它面向对象应用地非常好,基本上每一块儿都专门封装成一个类,但是对于app进行http请求来说,它又显得相对复杂很多。
而HttpURLConnection则非常简洁,所有的设置调用只通过这个API就可以了,并且它会自动处理gzip(虽然手动处理的代码也不多)。
结论
对于新开发的应用,肯定首选HttpURLConnection,HttpClient只用来维护一些比较老的代码。具体的差别见上面的总结。
- HttpClient与HttpURLConnection的区别(理论与实践结合)
- HTTPClient与HttpURLConnection的区别
- HttpURLConnection与 HttpClient 区别
- HttpClient与HttpUrlConnection区别
- HttpUrlConnection与HttpClient的区别 无代码
- HttpURLConnection与HttpClient的不同
- httpurlconnection与httpclient的使用
- HttpURLConnection与HttpClient区别及联系
- android中HttpUrlConnection与HttpClient区别
- HttpURLConnection与HttpClient区别及联系
- HttpURLConnection与HttpClient区别及联系
- HttpURLConnection与HttpClient区别及联系
- HttpURLConnection与HttpClient区别及联系
- HttpURLConnection与HttpClient区别及联系
- HttpURLConnection与HttpClient区别及联系
- HttpURLConnection与HttpClient 区别及联系
- HttpURLConnection与HttpClient区别及联系
- HttpURLConnection与HttpClient区别及联系
- SwipeRefreshLayout基本使用
- Apache性能优化、超时设置,linux 重启apache
- 友善之臂第二个裸板驱动蜂鸣器程序
- poj2449(第k短路)
- MFC网络编程
- HttpClient与HttpURLConnection的区别(理论与实践结合)
- Linux-CentOS 安装MP4Box
- Jq 下拉框chosen之后,动态改变dropdown的数据
- 笔记124--WebView
- 黑马程序员——C语言基础---指针3
- Java IO最详解
- 浏览器、apache的连接超时详解
- 响应有参方法
- android第四更 (DownManger 系统级下载文件)