前言html
HttpClient相對傳統JDK自帶的URLConnection,,增長了易用性和靈活性,它不只使客戶端發生HTTP請求變得容易,並且也方便了開發人員測試接口(基於HTTP協議),既提升了開發的效率,也提升了代碼的健壯性。所以熟練掌握HTTPClient是很重要的必修課,掌握httpclient後,相信對於HTTP協議的瞭解會更加深刻。java
1、簡介apache
httpclient是Apache Jakarta common下的子項目,用來提供高效的、最新的、更能豐富的支持http協議的客戶端編程工具包,而且它支持http協議最新的版本和建議。httpclient已經應用在不少項目中,好比Apache Jakarta上很著名的兩個開源項目cactus和httplunit都使用了httpclient。編程
2、特效服務器
1.基於標準、純淨的Java語言。實現了HTTP1.0和HTTP1.1session
2.以可擴展的面向對象的結構實現了HTTP所有的方法(GET、POST、put、delete、head、options、trace)。多線程
3.支持HTTPS協議。併發
4.經過HTTP代理創建透明的鏈接。socket
5.利用connect方法經過HTTP代理創建隧道的HTTPS鏈接。工具
6.basic,digest,htlmv1,htlmv2,htlm2 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 可免費獲取。
3、使用方法
使用HttpClient發送請求、接收響應很簡單,通常須要以下幾步便可。
一、建立httpclient對象。
二、建立請求方法的實例,並制定請求url。若是須要發送get請求,建立httpclient對象;若是須要發送post請求,建立httpPOST對象。
三、若是須要發送請求參數,可調用httpget、httpPost共同的setparams(HetpParams params)方法來添加請求參數;對於HttpPost對象而言,也可調用setEntity(HttpEntity entity)方法來設置請求參數。
四、調用HttpClient對象的execute(HttpUriRequest request)發送請求,該方法返回一個HttpResponse。
五、調用HttpResponse的getAllHeaders()、getHeaders(String name)等方法可獲取服務器的響應頭;調用HttpResponse的getEntity()方法可獲取HttpEntity對象,該對象包裝了服務器的響應內容。程序可經過該對象獲取服務器的響應內容。
六、釋放鏈接。不管執行方法是否成功,都必須釋放鏈接。
4、獲取頁面代碼
package http.HttpClient; import java.io.IOException; import java.util.ArrayList; import java.util.List; import org.apache.http.Consts; import org.apache.http.HttpEntity; import org.apache.http.HttpResponse; import org.apache.http.NameValuePair; import org.apache.http.client.ClientProtocolException; import org.apache.http.client.entity.UrlEncodedFormEntity; import org.apache.http.client.methods.HttpGet; import org.apache.http.client.methods.HttpPost; import org.apache.http.impl.client.DefaultHttpClient; import org.apache.http.message.BasicNameValuePair; import org.apache.http.util.EntityUtils; public class GetCode { public static void main(String[] args) throws ClientProtocolException, IOException { DefaultHttpClient httpclient = new DefaultHttpClient(); HttpGet httpGet = new HttpGet("http://www.baidu.com"); String body = ""; HttpResponse response; HttpEntity entity; response = httpclient.execute(httpGet); entity = response.getEntity(); body = EntityUtils.toString(entity);//這個就是頁面源碼了 httpGet.abort();//中斷請求,接下來能夠開始另外一段請求 System.out.println(body); //httpGet.releaseConnection();//釋放請求.若是釋放了至關於要清空session //如下是post方法 HttpPost httpPost = new HttpPost("http://www.baidu.com");//必定要改爲能夠提交的地址,這裏用百度代替 List <NameValuePair> nvps = new ArrayList <NameValuePair>(); nvps.add(new BasicNameValuePair("name", "1"));//名值對 nvps.add(new BasicNameValuePair("account", "xxxx")); httpPost.setEntity(new UrlEncodedFormEntity(nvps, Consts.UTF_8)); response = httpclient.execute(httpPost); entity = response.getEntity(); body = EntityUtils.toString(entity); System.out.println("Login form get: " + response.getStatusLine());//這個能夠打印狀態 httpPost.abort(); System.out.println(body); httpPost.releaseConnection(); } }
代碼實例
package http.HttpClient; import java.io.IOException; import java.io.InterruptedIOException; import java.net.UnknownHostException; import javax.net.ssl.SSLException; import javax.net.ssl.SSLHandshakeException; import org.apache.http.HttpEntityEnclosingRequest; import org.apache.http.HttpHost; import org.apache.http.HttpRequest; import org.apache.http.NoHttpResponseException; import org.apache.http.client.HttpRequestRetryHandler; import org.apache.http.client.config.RequestConfig; import org.apache.http.client.protocol.HttpClientContext; import org.apache.http.config.Registry; import org.apache.http.config.RegistryBuilder; import org.apache.http.conn.ConnectTimeoutException; import org.apache.http.conn.routing.HttpRoute; import org.apache.http.conn.socket.ConnectionSocketFactory; import org.apache.http.conn.socket.LayeredConnectionSocketFactory; import org.apache.http.conn.socket.PlainConnectionSocketFactory; import org.apache.http.conn.ssl.SSLConnectionSocketFactory; import org.apache.http.impl.client.CloseableHttpClient; import org.apache.http.impl.client.HttpClients; import org.apache.http.impl.conn.PoolingHttpClientConnectionManager; import org.apache.http.protocol.HttpContext; /** * org.apache.http.impl.client.CloseableHttpClient連接池生成工具 * @reference http://www.cnblogs.com/whatlonelytear/articles/4835538.html * @author King * @date 20170601 */ public class HttpClientTool { // org.apache.http.impl.client.CloseableHttpClient private static CloseableHttpClient httpclient = null; // 這裏就直接默認固定了,由於如下三個參數在新建的method中仍然能夠從新配置並被覆蓋. static final int connectionRequestTimeout = 5000;// ms毫秒,從池中獲取連接超時時間 static final int connectTimeout = 5000;// ms毫秒,創建連接超時時間 static final int socketTimeout = 30000;// ms毫秒,讀取超時時間 // 總配置,主要涉及是如下兩個參數,若是要做調整沒有用到properties會比較後麻煩,但鑑於一經粘貼,隨處可用的特色,就再也不作依賴性配置化處理了. // 並且這個參數同一家公司基本不會變更. static final int maxTotal = 500;// 最大總併發,很重要的參數 static final int maxPerRoute = 100;// 每路併發,很重要的參數 // 正常狀況這裏應該配成MAP或LIST // 細化配置參數,用來對每路參數作精細化處理,能夠管控各ip的流量,好比默認配置請求baidu:80端口最大100個併發連接, static final String detailHostName = "http://www.baidu.com";// 每一個細化配置之ip(不重要,在特殊場景頗有用) static final int detailPort = 80;// 每一個細化配置之port(不重要,在特殊場景頗有用) static final int detailMaxPerRoute = 100;// 每一個細化配置之最大併發數(不重要,在特殊場景頗有用) public static CloseableHttpClient getHttpClient() { if (null == httpclient) { synchronized (HttpClientTool.class) { if (null == httpclient) { httpclient = init(); } } } return httpclient; } /** * 連接池初始化 這裏最重要的一點理解就是. 讓CloseableHttpClient 一直活在池的世界裏, 可是HttpPost卻一直用完就消掉. * 這樣可讓連接一直保持着. * * @return */ private static CloseableHttpClient init() { CloseableHttpClient newHttpclient = null; // 設置鏈接池 ConnectionSocketFactory plainsf = PlainConnectionSocketFactory.getSocketFactory(); LayeredConnectionSocketFactory sslsf = SSLConnectionSocketFactory.getSocketFactory(); Registry<ConnectionSocketFactory> registry = RegistryBuilder.<ConnectionSocketFactory> create().register("http", plainsf).register("https", sslsf).build(); PoolingHttpClientConnectionManager cm = new PoolingHttpClientConnectionManager(registry); // 將最大鏈接數增長 cm.setMaxTotal(maxTotal); // 將每一個路由基礎的鏈接增長 cm.setDefaultMaxPerRoute(maxPerRoute); // 細化配置開始,其實這裏用Map或List的for循環來配置每一個連接,在特殊場景頗有用. // 將每一個路由基礎的鏈接作特殊化配置,通常用不着 HttpHost httpHost = new HttpHost(detailHostName, detailPort); // 將目標主機的最大鏈接數增長 cm.setMaxPerRoute(new HttpRoute(httpHost), detailMaxPerRoute); // cm.setMaxPerRoute(new HttpRoute(httpHost2), // detailMaxPerRoute2);//能夠有細化配置2 // cm.setMaxPerRoute(new HttpRoute(httpHost3), // detailMaxPerRoute3);//能夠有細化配置3 // 細化配置結束 // 請求重試處理 HttpRequestRetryHandler httpRequestRetryHandler = new HttpRequestRetryHandler() { public boolean retryRequest(IOException exception, int executionCount, HttpContext context) { if (executionCount >= 2) {// 若是已經重試了2次,就放棄 return false; } if (exception instanceof NoHttpResponseException) {// 若是服務器丟掉了鏈接,那麼就重試 return true; } if (exception instanceof SSLHandshakeException) {// 不要重試SSL握手異常 return false; } if (exception instanceof InterruptedIOException) {// 超時 return false; } if (exception instanceof UnknownHostException) {// 目標服務器不可達 return false; } if (exception instanceof ConnectTimeoutException) {// 鏈接被拒絕 return false; } if (exception instanceof SSLException) {// SSL握手異常 return false; } HttpClientContext clientContext = HttpClientContext.adapt(context); HttpRequest request = clientContext.getRequest(); // 若是請求是冪等的,就再次嘗試 if (!(request instanceof HttpEntityEnclosingRequest)) { return true; } return false; } }; // 配置請求的超時設置 RequestConfig requestConfig = RequestConfig.custom().setConnectionRequestTimeout(connectionRequestTimeout).setConnectTimeout(connectTimeout).setSocketTimeout(socketTimeout).build(); newHttpclient = HttpClients.custom().setConnectionManager(cm).setDefaultRequestConfig(requestConfig).setRetryHandler(httpRequestRetryHandler).build(); return newHttpclient; } } httpclient實例 import java.io.IOException; import java.net.UnknownHostException; import java.io.InputStream; import java.io.OutputStream; import java.io.FileOutputStream; import org.apache.http.HttpEntity; import org.apache.http.impl.client.CloseableHttpClient; import org.apache.http.impl.client.HttpClients; import org.apache.http.client.methods.HttpGet; import org.apache.http.client.methods.CloseableHttpResponse; import org.apache.http.message.AbstractHttpMessage; public class Simplest { private void Get() { CloseableHttpClient httpclient = HttpClients.createDefault(); try { String HostName = "http://www.baidu.com"; HttpGet httpget = new HttpGet(HostName); System.out.println(httpget.getURI()); //HttpGet httpget = new HttpGet("http://www.lietu.com"); CloseableHttpResponse response = httpclient.execute(httpget); System.out.println("Successful!"); System.out.println(response.getProtocolVersion()); //Protocol Version System.out.println(response.getStatusLine().getStatusCode()); //Status Code System.out.println(response.getStatusLine().getReasonPhrase()); System.out.println(response.getStatusLine().toString()); //get entity HttpEntity entity = response.getEntity(); if (entity != null) { InputStream input = entity.getContent(); String filename = HostName.substring(HostName.lastIndexOf('/')+1); System.out.println("The filename is: " + filename); OutputStream output = new FileOutputStream(filename); int tempByte=-1; while ((tempByte=input.read())>0) { output.write(tempByte); } if (input != null) { input.close(); } if (output != null) { output.close(); } } } catch(UnknownHostException e) { System.out.println("No such a host!"); } catch(IOException e) { e.printStackTrace(); } } public static void main(String[] args) { Simplest a = new Simplest(); a.Get(); System.out.println("This is a test"); } }