第一章 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) {    //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(),用於外部類來獲取該內部類的實例。當然,如果對於內部類不熟的話,可以不使用內部類,直接使用上邊的方式也好。

  

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM