[HttpClient] HttpClient 使用

Http协议的重要性相信不用我多说了,HttpClient相比传统JDK自带的URLConnection,增加了易用性和灵活性(具体区别,日后我们再讨论),它不仅是客户端发送Http请求变得容易,而且也方便了开发人员测试接口(基于Http协议的),即提高了开发的效率,也方便提高代码的健壮性。因此熟练掌握HttpClient是很重要的必修内容,掌握HttpClient后,相信对于Http协议的了解会更加深入。

一、简介

HttpClient是Apache Jakarta Common下的子项目,用来提供高效的、最新的、功能丰富的支持HTTP协议的客户端编程工具包,并且它支持HTTP协议最新的版本和建议。HttpClient已经应用在很多的项目中,比如Apache Jakarta上很著名的另外两个开源项目Cactus和HTMLUnit都使用了HttpClient。

下载地址: http://hc.apache.org/downloads.cgi

二、特性

1. 基于标准、纯净的java语言。实现了Http1.0和Http1.1

2. 以可扩展的面向对象的结构实现了Http全部的方法(GET, POST, PUT, DELETE, HEAD, OPTIONS, and TRACE)。

3. 支持HTTPS协议。

4. 通过Http代理建立透明的连接。

5. 利用CONNECT方法通过Http代理建立隧道的https连接。

6. Basic, Digest, NTLMv1, NTLMv2, NTLM2 Session, SNPNEGO/Kerberos认证方案。

7. 插件式的自定义认证方案。

8. 便携可靠的套接字工厂使它更容易的使用第三方解决方案。

9. 连接管理器支持多线程应用。支持设置最大连接数,同时支持设置每个主机的最大连接数,发现并关闭过期的连接。

10. 自动处理Set-Cookie中的Cookie。

11. 插件式的自定义Cookie策略。

12. Request的输出流可以避免流中内容直接缓冲到socket服务器。

13. Response的输入流可以有效的从socket服务器直接读取相应内容。

14. 在http1.0和http1.1中利用KeepAlive保持持久连接。

15. 直接获取服务器发送的response code和 headers。

16. 设置连接超时的能力。

17. 实验性的支持http1.1 response caching。

18. 源代码基于Apache License 可免费获取。

四、示例

HttpClient作为访问Http服务的客户端访问程序已经被广泛使用,对于HttpClient的使用方法也有很多blog进行介绍,本文简明扼要的介绍HttpClient的两种使用方式——简单连接管理的HttpClient(BasicClientConnectionManager)和池化的HttpClient(PoolingClientConnectionManager)。

HttpClient从4.2开始抛弃了先前的SingleClientConnManager和ThreadSafeConnManger,取而代之的是BasicClientConnectionManager和PoolingClientConnectionManager。

BasicClientConnectionManager内部只维护一个活动的connection,尽管这个类是线程安全的,但是最好在一个单独的线程中重复使用它。如果在同一个BasicClientConnectionManager对象中,多次执行http请求,后继请求与先前请求是同一个route,那么BasicClientConnectionManager会使用同一个连接完成后续请求,否则,BasicClientConnectionManager会将先前的connection关闭,然后为后续请求创建一个新的连接。换句话说,BasicClientConnectionManager会尽力复用先前的连接(注意:创建连接和销毁连接都是不小的开销),因此,如果对同一个service有多个连续请求,应该尽量使用同一个BasicClientConnectionManager完成。

PoolingClientConnectionManager可以在多线程中使用,连接按照route被缓存(pooled),当后续的请求route已经在pool中存在,就会使用pool中先前使用的connection获取请求结果。PoolingClientConnectionManager对每个router维护的connection数目有上限要求,默认情况下,每个router最多维护两个并发线程的connection连接,整个pool最多容纳20个并发的connections。当然可以通过设置来修改这些限制。

案例一、

使用最简单的方式创建的httpclient内部使用的是BasicClientConnectionManager管理连接,并且使用HttpClient提供的EntityUtils将消息体转换成String输出。httpClient对象可以被重复使用,执行多个http请求,当你真正不需要他的时候,记得调用shutdown,关闭并且释放占用的资源。

package com.wa.dataprocess.test;

import java.io.IOException;
import java.nio.charset.Charset;

import org.apache.http.Header;
import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.util.EntityUtils;


public class HttpClientTest {
    
    public static void main(String[] args) {
        
        HttpClient client = new DefaultHttpClient();
        
        //创建get请求实例
        HttpGet get = new HttpGet("http://www.baidu.com");
        
         System.out.println("请求的uri为:"+get.getURI());    
         
         try {
            // 客户端执行get请求 返回响应实体  
            HttpResponse response = client.execute(get);
            
            //获取请求状态行 
            System.out.println("请求状态行为:"+response.getStatusLine());
            
        //获取所有的请求头    
        Header[] headers=response.getAllHeaders();
        
        for (Header header :headers){
            //遍历获取所有请求头的名称和值
        System.out.println(header.getName()+" :--: "+header.getValue());    
        }
        System.out.println("-----------------------------------------------");
        //获取响应的实体
        HttpEntity entity =response.getEntity();
        
        if (entity!=null){
            System.out.println(EntityUtils.toString(entity,Charset.forName("UTF-8")));
            System.out.println("=================================");
            System.out.println("内容长度为:"+entity.getContentLength());
        }
        } catch (ClientProtocolException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }finally{
            //释放连接 
            client.getConnectionManager().shutdown();
        }
        
        
         
       
    }

}

最基本的使用,输出信息为:

请求的uri为:http://www.baidu.com
请求状态行为:HTTP/1.1 200 OK


Date   :--: Thu, 19 Mar 2015 08:54:00 GMT
Content-Type    :--: text/html; charset=utf-8
Transfer-Encoding    :--: chunked
Connection   :--: Keep-Alive
Vary   :--: Accept-Encoding
Set-Cookie   :--: BAIDUID=EAC4016D4235E694E4EEBF4327D19E44:FG=1; expires=Thu, 31-Dec-37 23:55:55 GMT; max-age=2147483647; path=/; domain=.baidu.com
Set-Cookie :--: BIDUPSID=EAC4016D4235E694E4EEBF4327D19E44; expires=Thu, 31-Dec-37 23:55:55 GMT; max-age=2147483647; path=/; domain=.baidu.com
Set-Cookie :--: BDSVRTM=0; path=/
Set-Cookie :--: BD_HOME=0; path=/
Set-Cookie :--: H_PS_PSSID=11327_1468_12788_12882_12824_12574_12691_12694_12901_12849_12723_12797_12737_12782_8498; path=/; domain=.baidu.com
P3P :--: CP=" OTI DSP COR IVA OUR IND COM "
Cache-Control :--: private
Cxy_all :--: baidu+0a4b635a28477f8a9ebd7fb1cdbeb840
Expires :--: Thu, 19 Mar 2015 08:53:08 GMT
X-Powered-By :--: HPHP
Server :--: BWS/1.1
BDPAGETYPE :--: 1
BDQID :--: 0xc6a9b12700007937
BDUSERID :--: 0
-----------------------------------------------

/*这里是百度首页的源代码,好大一坨,就留这么多吧.....*/
<!DOCTYPE html><!--STATUS OK--><html><head><meta http-equiv="content-type" content="text/html;charset=utf-8"><meta http-equiv="X-UA-Compatible" content="IE=Edge"><meta content="always" name="referrer"><link rel="dns-prefetch" href="//s1.bdstatic.com"/><link rel="dns-<script>if(navigator.cookieEnabled){document.cookie="NOJS=;expires=Sat, 01 Jan 2000 00:00:00 GMT";}</script></body></html>

=================================
内容长度为:-1

 

案例二、

PoolingClientConnectionManager的创建过程要比BasicClientConnectionManager复杂的多,当然,我们为了举例子,将PoolingClientConnectionManager可能涉及到的多个方面属性都列出来,可以根据需要设置或者使用默认的连接属性。首先我们创建了SchemeRegistry,之后注册了两种http访问方式http和https,创建PoolingClientConnectionManager,指定每个router最多保持20个活动的connection,这个pool最多保持200个活动的connection,对本地的访问可以保持80个活动的connection。最后创建httpClient,设置SO_TIMEOUT和CONNECTION_TIMEOUT,执行请求。在httpClient不再使用时,关闭connectionManager。

package com.wa.dataprocess.test;

import java.nio.charset.Charset;

import javax.net.ssl.SSLContext;

import org.apache.http.HttpHost;
import org.apache.http.HttpResponse;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.conn.routing.HttpRoute;
import org.apache.http.conn.scheme.PlainSocketFactory;
import org.apache.http.conn.scheme.Scheme;
import org.apache.http.conn.scheme.SchemeRegistry;
import org.apache.http.conn.ssl.SSLSocketFactory;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.impl.conn.PoolingClientConnectionManager;
import org.apache.http.params.HttpConnectionParams;
import org.apache.http.params.HttpParams;
import org.apache.http.util.EntityUtils;

/**
 * 基于
 * @author Administrator
 *
 */
public class PoolHttpClient {
    
    public static void main(String[] args) {
        //创建schema
        SchemeRegistry registry = new SchemeRegistry();
        
         HttpClient httpClient =null;
        
        try {
            //https类型的消息访问
            SSLContext context = SSLContext.getInstance("SSL");
            context.init(null,null,null);
            
             SSLSocketFactory sslFactory = new SSLSocketFactory(context,SSLSocketFactory.STRICT_HOSTNAME_VERIFIER);
               registry.register(new Scheme("http", 80, PlainSocketFactory.getSocketFactory()));//http 80 端口
               registry.register(new Scheme("https", 443, sslFactory));//https 443端口
              
               PoolingClientConnectionManager cm =new PoolingClientConnectionManager(registry);//创建connectionManager
              
               cm.setDefaultMaxPerRoute(20);//对每个指定连接的服务器(指定的ip)可以创建并发20 socket进行访问
               cm.setMaxTotal(200);//创建socket的上线是200
               HttpHost localhost = new HttpHost("locahost", 80);
               cm.setMaxPerRoute(new HttpRoute(localhost), 80);//对本机80端口的socket连接上限是80
              
              httpClient = new DefaultHttpClient(cm);//使用连接池创建连接
               HttpParams params = httpClient.getParams();
               HttpConnectionParams.setSoTimeout(params, 60*1000);//设定连接等待时间
               HttpConnectionParams.setConnectionTimeout(params, 60*1000);//设定超时时间
         
                 HttpGet httpGet = new HttpGet("http://m.weather.com.cn/data/101010100.html");
                   HttpResponse response = httpClient.execute(httpGet);
                   String result = EntityUtils.toString(response.getEntity(), Charset.forName("utf-8"));
              System.out.println(result);
            
        } catch (Exception e) {
            e.printStackTrace();
        }finally{
            httpClient.getConnectionManager().shutdown();
        }
        
    }

}

返回内容:

 

<html>
<head>
</head>
<body>
<script type="text/javascript">
window.onload = function() {
window.open("/","_self");
};
</script>
<!-- START WRating v1.0 -->
<script type="text/javascript" src="http://c.wrating.com/a1.js">
</script>
<script type="text/javascript">
var vjAcc="860010-2151010100";
var wrUrl="http://c.wrating.com/";
vjTrack("");
</script>
<noscript><img src="http://c.wrating.com/a.gif?a=&c=860010-2151010100" width="1" height="1"/></noscript>
<!-- END WRating v1.0 -->
</body>
</html>

 

参考文章:

http://blog.csdn.net/wangpeng047/article/details/19624529

 

http://blog.sina.com.cn/s/blog_616e189f01018rpk.html

posted @ 2015-03-19 17:22  snow__wolf  阅读(411)  评论(0)    收藏  举报