1、http協議(這一塊兒有時間的話會做記錄)2、常用的兩種RPC方式基於http協議:HttpClient和JDK自己的Http操作類基於TCP或UDP協議:mina2和netty(這一部分以後有時間做記錄)3、HttpClient工具類的編寫(只列出了兩個最常用的方法get和post)使用場合:...
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介面,並實現其中的三個方法。註意:這個類的註釋一定要看
第一種方法需要手工導入證書,很費事;第二種方法十分靈活。
- 對於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();// 中止請求,連接被釋放回連接池