你的位置:首页 > Java教程

[Java教程]第一章 HttpClient的使用


1、http协议(这一块儿有时间的话会做记录)

2、常用的两种RPC方式

  • 基于http协议:HttpClient和JDK自己的Http操作类
  • 基于TCP或UDP协议:mina2和netty(这一部分以后有时间做记录)

3、HttpClient工具类的编写(只列出了两个最常用的方法get和post)

使用场合:我们可以在网页发送get或post请求去访问服务器server1,那我们在Java程序中想要模拟网页向服务器server1发送get和post请求的时候怎么办?--用HttpClient

版本:httpClient4.2.6(jar或者maven坐标自己加上)

maven坐标:

1 <dependency>2   <groupId>org.apache.httpcomponents</groupId>3   <artifactId>httpclient</artifactId>4   <version>4.2.6</version>5 </dependency>

View Code

代码实现(两个类):

MyX509TrustManager(自定义的信任管理器) 

 1 package com.util; 2  3 import java.security.cert.CertificateException; 4 import java.security.cert.X509Certificate; 5  6 import javax.net.ssl.X509TrustManager; 7  8 /** 9  * 自定义的信任管理器10 */11 public class MyX509TrustManager implements X509TrustManager {12   /**13    * 检查客户端证书,若不信任,抛出异常14   */15   public void checkClientTrusted(X509Certificate[] arg0, String arg1)16       throws CertificateException {17   }18   /**19    * 检查服务端证书,若不信任,抛出异常,反之,若不抛出异常,则表示信任(所以,空方法代表信任所有的服务端证书)20   */21   public void checkServerTrusted(X509Certificate[] arg0, String arg1)22       throws CertificateException {23   }24   /**25    * 返回受信任的X509证书数组26   */27   public X509Certificate[] getAcceptedIssuers() {28     return null;29   }30 }

View Code

 HttpClientUtil:

 1 package com.util; 2  3 import java.io.IOException; 4 import java.security.KeyManagementException; 5 import java.security.NoSuchAlgorithmException; 6 import java.security.NoSuchProviderException; 7 import java.security.SecureRandom; 8 import java.util.ArrayList; 9 import java.util.List; 10 import java.util.Map; 11 import java.util.Properties; 12 import java.util.Set; 13  14 import javax.net.ssl.SSLContext; 15 import javax.net.ssl.TrustManager; 16  17 import org.apache.commons.collections4.MapUtils; 18 import org.apache.http.HttpEntity; 19 import org.apache.http.HttpResponse; 20 import org.apache.http.HttpStatus; 21 import org.apache.http.HttpVersion; 22 import org.apache.http.NameValuePair; 23 import org.apache.http.StatusLine; 24 import org.apache.http.client.ClientProtocolException; 25 import org.apache.http.client.HttpClient; 26 import org.apache.http.client.entity.UrlEncodedFormEntity; 27 import org.apache.http.client.methods.HttpGet; 28 import org.apache.http.client.methods.HttpPost; 29 import org.apache.http.client.utils.URLEncodedUtils; 30 import org.apache.http.conn.scheme.PlainSocketFactory; 31 import org.apache.http.conn.scheme.Scheme; 32 import org.apache.http.conn.scheme.SchemeRegistry; 33 import org.apache.http.conn.ssl.SSLSocketFactory; 34 import org.apache.http.impl.client.DefaultHttpClient; 35 import org.apache.http.impl.conn.PoolingClientConnectionManager; 36 import org.apache.http.message.BasicNameValuePair; 37 import org.apache.http.params.BasicHttpParams; 38 import org.apache.http.params.CoreConnectionPNames; 39 import org.apache.http.params.CoreProtocolPNames; 40 import org.apache.http.params.HttpParams; 41 import org.apache.http.util.EntityUtils; 42  43 /** 44  * 对HTTPClient的封装 45 */ 46 public class HttpClientUtil { 47  48   private static final String ENCODING = "UTF-8"; 49  50   private static HttpClient client = null; 51   private static SchemeRegistry schemeRegistry;    //协议控制 52   private static PoolingClientConnectionManager ccm; //HttpClient连接池(多连接的线程安全的管理器) 53  54   static { 55     try { 56       /* 57        * 与https请求相关的操作 58       */ 59       SSLContext sslContext = SSLContext.getInstance("SSL","SunJSSE"); 60       sslContext.init(null, new TrustManager[]{new MyX509TrustManager()}, new SecureRandom()); 61       SSLSocketFactory socketFactory = new SSLSocketFactory(sslContext); 62       /* 63        * 定义访问协议 64       */ 65       schemeRegistry = new SchemeRegistry(); 66       schemeRegistry.register(new Scheme("http", 80, PlainSocketFactory.getSocketFactory()));//http 67       schemeRegistry.register(new Scheme("https", 443, socketFactory));//https 68     } catch (NoSuchAlgorithmException e) { 69       e.printStackTrace(); 70     } catch (NoSuchProviderException e) { 71       e.printStackTrace(); 72     } catch (KeyManagementException e) { 73       e.printStackTrace(); 74     } 75      76     Properties props = FileUtil.loadProps("http.properties");//加载属性文件 77      78     // 连接池管理 79     ccm = new PoolingClientConnectionManager(schemeRegistry); 80     ccm.setDefaultMaxPerRoute(FileUtil.getInt(props, "httpclient.max.conn.per.route", 20));//每个路由的最大连接数 81     ccm.setMaxTotal(FileUtil.getInt(props, "httpclient.max.conn.total", 400));//最大总连接数 82  83     HttpParams httpParams = new BasicHttpParams(); 84     httpParams.setParameter(CoreConnectionPNames.CONNECTION_TIMEOUT, FileUtil.getInt(props, "httpclient.max.conn.timeout", 1000));//连接超时时间(ms) 85     httpParams.setParameter(CoreConnectionPNames.SO_TIMEOUT, FileUtil.getInt(props, "httpclient.max.socket.timeout", 2000));//操作超时时间(ms) 86     httpParams.setParameter(CoreProtocolPNames.PROTOCOL_VERSION,HttpVersion.HTTP_1_1);//设置http1.1或http1.0 87  88     client = new DefaultHttpClient(ccm, httpParams);//一个客户端就有一个连接池 89   } 90  91   /** 92    * get请求 93    * @param url    请求URL 94    * @param paramMap  请求参数 95    * @param headerMap  请求头信息 96   */ 97   public static String get(String url, 98               Map<String, String> paramMap,  99               Map<String, String> headerMap) throws ClientProtocolException, 100                                   IOException {101     /*102      * 拼接URL与参数103     */104     if (MapUtils.isNotEmpty(paramMap)) {105       List<NameValuePair> params = new ArrayList<NameValuePair>();106       for (String key : paramMap.keySet()) {107         params.add(new BasicNameValuePair(key, paramMap.get(key)));108       }109       String queryString = URLEncodedUtils.format(params,ENCODING);110       if (url.indexOf("?") > -1) {//存在?,表示这时的URL已经带参数了111         url += "&" + queryString;112       } else {113         url += "?" + queryString;114       }115     }116 117     HttpGet httpGet = new HttpGet(url);118 119     /*120      * 设置头信息121     */122     if (MapUtils.isNotEmpty(headerMap)) {123       Set<String> keySet = headerMap.keySet();124       for (String key : keySet) {125         httpGet.addHeader(key, headerMap.get(key));126       }127     }128 129     String result = "";130     131     HttpResponse response = client.execute(httpGet);  //发出get请求132     StatusLine status = response.getStatusLine();    //获取返回的状态码133     HttpEntity entity = response.getEntity();      //获取返回的响应内容134     if (status.getStatusCode() == HttpStatus.SC_OK) {  //200135       result = EntityUtils.toString(entity, ENCODING);136     } 137     138     httpGet.abort();//中止请求,连接被释放回连接池139     return result;140   }141 142   /**143    * post请求144    * @param url    //请求URL145    * @param paramMap  //请求参数146    * @param headerMap  //请求头信息147   */148   public static String post(String url,149                Map<String, String> paramMap, 150                Map<String, String> headerMap) throws ClientProtocolException, 151                                    IOException {152     HttpPost httpPost = new HttpPost(url);153     /*154      * 处理参数155     */156     List<NameValuePair> params = new ArrayList<NameValuePair>();157     if (MapUtils.isNotEmpty(paramMap)) {158       Set<String> keySet = paramMap.keySet();159       for (String key : keySet) {160         params.add(new BasicNameValuePair(key, paramMap.get(key)));161       }162     }163 164     /*165      * 设置头信息166     */167     if (MapUtils.isNotEmpty(headerMap)) {168       Set<String> keySet = headerMap.keySet();169       for (String key : keySet) {170         httpPost.addHeader(key, headerMap.get(key));171       }172     }173 174     String result = "";175     176     httpPost.setEntity(new UrlEncodedFormEntity(params, ENCODING));//设置参数177     HttpResponse response = client.execute(httpPost);        //发出post请求178     StatusLine status = response.getStatusLine();          //获取返回的状态码179     HttpEntity entity = response.getEntity();            //获取响应内容180     if (status.getStatusCode() == HttpStatus.SC_OK) {181       result = EntityUtils.toString(entity, ENCODING);182     }183     184     httpPost.abort();//中止请求,连接被释放回连接池185     return result;186   }187 188   /**189    * 测试190   */191   public static void main(String[] args) {192     try {193       System.out.println(HttpClientUtil.get("https://www.baidu.com/", null, null));194       //System.out.println(HttpClientUtil.post("http://www.cppblog.com/iuranus/archive/2010/07/04/119311.html", null, null));195     } catch (ClientProtocolException e) {196       e.printStackTrace();197     } catch (IOException e) {198       e.printStackTrace();199     }200   }201 }

View Code

在该代码中,还有两个部分:一个属性文件http.properties和一个文件操作类FileUtil。这两部分,请查看下边的这个链接:

http://www.cnblogs.com/java-zhao/p/5098813.html

注意:

  • 我们发起的请求可以使http的,也可以是https(相当于http+SSL/TLS+数字证书的组合,是一种安全协议)的,对于https相关的请求而言,我们需要编写一些代码,来做特殊的处理。一般而言,处理https请求有两种方法:

  1)将https服务器端的安全证书导入到客户端的TrustStore文件中去,具体的原理见"《微信公众平台应用开发(方法、技巧与案例)》第5章"或者去查看柳峰的博客

    2)实现自定义的信任管理器(eg.MyX509TrustManager),需要实现X509TrustManager接口,并实现其中的三个方法。注意:这个类的注释一定要看

        第一种方法需要手工导入证书,很费事;第二种方法十分灵活

  • 对于HttpClientUtil中,每一块做什么查看注释,这里:解释httpclient.max.conn.per.route(每个路由的最大连接数):这里路由的概念可以理解为"运行环境机器到目标机器"的一条线路。举例来说,我们使用HttpClient的实现来分别请求 www.baidu.com 的资源和 www.bing.com 的资源那么他就会产生两个route(路由),根据如上设置为20,就可以为上边两条route分别设置最大20个并发连接数。
  • 假如只有HttpClientUtil使用MyX509TrustManager,我们也可以将MyX509TrustManager作为HttpClientUtil的一个内部类,代码如下:
  •  1 package com.util; 2  3 import java.io.IOException; 4 import java.security.KeyManagementException; 5 import java.security.NoSuchAlgorithmException; 6 import java.security.NoSuchProviderException; 7 import java.security.SecureRandom; 8 import java.security.cert.CertificateException; 9 import java.security.cert.X509Certificate; 10 import java.util.ArrayList; 11 import java.util.List; 12 import java.util.Map; 13 import java.util.Properties; 14 import java.util.Set; 15  16 import javax.net.ssl.SSLContext; 17 import javax.net.ssl.TrustManager; 18 import javax.net.ssl.X509TrustManager; 19  20 import org.apache.commons.collections4.MapUtils; 21 import org.apache.http.HttpEntity; 22 import org.apache.http.HttpResponse; 23 import org.apache.http.HttpStatus; 24 import org.apache.http.HttpVersion; 25 import org.apache.http.NameValuePair; 26 import org.apache.http.StatusLine; 27 import org.apache.http.client.ClientProtocolException; 28 import org.apache.http.client.HttpClient; 29 import org.apache.http.client.entity.UrlEncodedFormEntity; 30 import org.apache.http.client.methods.HttpGet; 31 import org.apache.http.client.methods.HttpPost; 32 import org.apache.http.client.utils.URLEncodedUtils; 33 import org.apache.http.conn.scheme.PlainSocketFactory; 34 import org.apache.http.conn.scheme.Scheme; 35 import org.apache.http.conn.scheme.SchemeRegistry; 36 import org.apache.http.conn.ssl.SSLSocketFactory; 37 import org.apache.http.impl.client.DefaultHttpClient; 38 import org.apache.http.impl.conn.PoolingClientConnectionManager; 39 import org.apache.http.message.BasicNameValuePair; 40 import org.apache.http.params.BasicHttpParams; 41 import org.apache.http.params.CoreConnectionPNames; 42 import org.apache.http.params.CoreProtocolPNames; 43 import org.apache.http.params.HttpParams; 44 import org.apache.http.util.EntityUtils; 45  46 /** 47  * 对HTTPClient的封装 48 */ 49 public class HttpClientUtilWithMyX509TrustMananer { 50  51   private static final String ENCODING = "UTF-8"; 52  53   private static HttpClient client = null; 54   private static SchemeRegistry schemeRegistry; // 协议控制 55   private static PoolingClientConnectionManager ccm; // HttpClient连接池(多连接的线程安全的管理器) 56  57   static { 58     try { 59       /* 60        * 与https请求相关的操作 61       */ 62       SSLContext sslContext = SSLContext.getInstance("SSL", "SunJSSE"); 63       sslContext.init(null, 64               new TrustManager[] { getMyX509TrustManager() }, 65               new SecureRandom()); 66       SSLSocketFactory socketFactory = new SSLSocketFactory(sslContext); 67       /* 68        * 定义访问协议 69       */ 70       schemeRegistry = new SchemeRegistry(); 71       schemeRegistry.register(new Scheme("http", 80, PlainSocketFactory.getSocketFactory()));// http 72       schemeRegistry.register(new Scheme("https", 443, socketFactory));// https 73     } catch (NoSuchAlgorithmException e) { 74       e.printStackTrace(); 75     } catch (NoSuchProviderException e) { 76       e.printStackTrace(); 77     } catch (KeyManagementException e) { 78       e.printStackTrace(); 79     } 80  81     Properties props = FileUtil.loadProps("http.properties");// 加载属性文件 82  83     // 连接池管理 84     ccm = new PoolingClientConnectionManager(schemeRegistry); 85     ccm.setDefaultMaxPerRoute(FileUtil.getInt(props,"httpclient.max.conn.per.route", 20));// 每个路由的最大连接数 86     ccm.setMaxTotal(FileUtil.getInt(props, "httpclient.max.conn.total", 400));// 最大总连接数 87  88     HttpParams httpParams = new BasicHttpParams(); 89     httpParams.setParameter(CoreConnectionPNames.CONNECTION_TIMEOUT,FileUtil.getInt(props, "httpclient.max.conn.timeout", 1000));// 连接超时时间(ms) 90     httpParams.setParameter(CoreConnectionPNames.SO_TIMEOUT,FileUtil.getInt(props, "httpclient.max.socket.timeout", 2000));// 操作超时时间(ms) 91     httpParams.setParameter(CoreProtocolPNames.PROTOCOL_VERSION,HttpVersion.HTTP_1_1);// 设置http1.1或http1.0 92  93     client = new DefaultHttpClient(ccm, httpParams);// 一个客户端就有一个连接池 94   } 95  96   /** 97    * get请求 98    * @param url    请求URL 99    * @param paramMap 请求参数100    * @param headerMap 请求头信息101   */102   public static String get(String url, 103               Map<String, String> paramMap,104               Map<String, String> headerMap) throws ClientProtocolException,105                                   IOException {106     /*107      * 拼接URL与参数108     */109     if (MapUtils.isNotEmpty(paramMap)) {110       List<NameValuePair> params = new ArrayList<NameValuePair>();111       for (String key : paramMap.keySet()) {112         params.add(new BasicNameValuePair(key, paramMap.get(key)));113       }114       String queryString = URLEncodedUtils.format(params, ENCODING);115       if (url.indexOf("?") > -1) {// 存在?,表示这时的URL已经带参数了116         url += "&" + queryString;117       } else {118         url += "?" + queryString;119       }120     }121 122     HttpGet httpGet = new HttpGet(url);123 124     /*125      * 设置头信息126     */127     if (MapUtils.isNotEmpty(headerMap)) {128       Set<String> keySet = headerMap.keySet();129       for (String key : keySet) {130         httpGet.addHeader(key, headerMap.get(key));131       }132     }133 134     String result = "";135 136     HttpResponse response = client.execute(httpGet); // 发出get请求137     StatusLine status = response.getStatusLine(); // 获取返回的状态码138     HttpEntity entity = response.getEntity(); // 获取返回的响应内容139     if (status.getStatusCode() == HttpStatus.SC_OK) { // 200140       result = EntityUtils.toString(entity, ENCODING);141     }142 143     httpGet.abort();// 中止请求,连接被释放回连接池144     return result;145   }146 147   /**148    * post请求149    * @param url    请求URL150    * @param paramMap 请求参数151    * @param headerMap 请求头信息152   */153   public static String post(String url, 154                Map<String, String> paramMap,155                Map<String, String> headerMap) throws ClientProtocolException,156                                    IOException {157     HttpPost httpPost = new HttpPost(url);158     /*159      * 处理参数160     */161     List<NameValuePair> params = new ArrayList<NameValuePair>();162     if (MapUtils.isNotEmpty(paramMap)) {163       Set<String> keySet = paramMap.keySet();164       for (String key : keySet) {165         params.add(new BasicNameValuePair(key, paramMap.get(key)));166       }167     }168 169     /*170      * 设置头信息171     */172     if (MapUtils.isNotEmpty(headerMap)) {173       Set<String> keySet = headerMap.keySet();174       for (String key : keySet) {175         httpPost.addHeader(key, headerMap.get(key));176       }177     }178 179     String result = "";180 181     httpPost.setEntity(new UrlEncodedFormEntity(params, ENCODING));// 设置参数182     HttpResponse response = client.execute(httpPost); // 发出post请求183     StatusLine status = response.getStatusLine(); // 获取返回的状态码184     HttpEntity entity = response.getEntity(); // 获取响应内容185     if (status.getStatusCode() == HttpStatus.SC_OK) {186       result = EntityUtils.toString(entity, ENCODING);187     }188 189     httpPost.abort();// 中止请求,连接被释放回连接池190     return result;191   }192 193   /**194    * 构建自定义信任管理器内部类195   */196   private static class MyX509TrustManager implements X509TrustManager {197     /**198      * 检查客户端证书,若不信任,抛出异常199     */200     public void checkClientTrusted(X509Certificate[] arg0, String arg1)201         throws CertificateException {202     }203     /**204      * 检查服务端证书,若不信任,抛出异常,反之,若不抛出异常,则表示信任(所以,空方法代表信任所有的服务端证书)205     */206     public void checkServerTrusted(X509Certificate[] arg0, String arg1)207         throws CertificateException {208     }209     /**210      * 返回受信任的X509证书数组211     */212     public X509Certificate[] getAcceptedIssuers() {213       return null;214     }215   }216 217   /**218    * 为外部类获取内部类提供方法219   */220   public static MyX509TrustManager getMyX509TrustManager() {221     return new MyX509TrustManager();222   }223 224   /**225    * 测试226   */227   public static void main(String[] args) {228     try {229       System.out.println(HttpClientUtilWithMyX509TrustMananer.get("https://www.baidu.com/", null, null));230       // System.out.println(HttpClientUtil.post("http://www.cppblog.com/iuranus/archive/2010/07/04/119311.html", null, null));231     } catch (ClientProtocolException e) {232       e.printStackTrace();233     } catch (IOException e) {234       e.printStackTrace();235     }236   }237 }

    View Code

    注:在这里我定义了一个成员内部类,并提供了一个获取成员内部类的方法getMyX509TrustManager(),用于外部类来获取该内部类的实例。当然,如果对于内部类不熟的话,可以不使用内部类,直接使用上边的方式也好。