赵计刚
每天进步一点点

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) {    //200
135             result = EntityUtils.toString(entity, ENCODING);
136         } 
137         
138         httpGet.abort();//中止请求,连接被释放回连接池
139         return result;
140     }
141 
142     /**
143      * post请求
144      * @param url        //请求URL
145      * @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接口,并实现其中的三个方法。注意:这个类的注释一定要看

    3)注意http大多数时候用的是8080端口而不是80

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

  • 对于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) { // 200
    140             result = EntityUtils.toString(entity, ENCODING);
    141         }
    142 
    143         httpGet.abort();// 中止请求,连接被释放回连接池
    144         return result;
    145     }
    146 
    147     /**
    148      * post请求
    149      * @param url       请求URL
    150      * @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(),用于外部类来获取该内部类的实例。当然,如果对于内部类不熟的话,可以不使用内部类,直接使用上边的方式也好。

  

 

posted on 2016-01-04 15:27  赵计刚  阅读(9026)  评论(0编辑  收藏  举报