httpclient 学习
Http協(xié)議的重要性相信不用我多說了,HttpClient相比傳統(tǒng)JDK自帶的URLConnection,增加了易用性和靈活性,它不僅是客戶端發(fā)送Http請求變得容易,而且也方便了開發(fā)人員測試接口(基于Http協(xié)議的),即提高了開發(fā)的效率,也方便提高代碼的健壯性。因此熟練掌握HttpClient是很重要的必修內(nèi)容,掌握HttpClient后,相信對于Http協(xié)議的了解會更加深入。
一、簡介
HttpClient是Apache Jakarta Common下的子項目,用來提供高效的、最新的、功能豐富的支持HTTP協(xié)議的客戶端編程工具包,并且它支持HTTP協(xié)議最新的版本和建議。HttpClient已經(jīng)應(yīng)用在很多的項目中,比如Apache Jakarta上很著名的另外兩個開源項目Cactus和HTMLUnit都使用了HttpClient。
?
二、特性
1. 基于標(biāo)準(zhǔn)、純凈的Java語言。實現(xiàn)了Http1.0和Http1.1
2. 以可擴(kuò)展的面向?qū)ο蟮慕Y(jié)構(gòu)實現(xiàn)了Http全部的方法(GET, POST, PUT, DELETE, HEAD, OPTIONS, and TRACE)。
3. 支持HTTPS協(xié)議。
4. 通過Http代理建立透明的連接。
5. 利用CONNECT方法通過Http代理建立隧道的https連接。
6. Basic, Digest, NTLMv1, NTLMv2, NTLM2 Session, SNPNEGO/Kerberos認(rèn)證方案。
7. 插件式的自定義認(rèn)證方案。
8. 便攜可靠的套接字工廠使它更容易的使用第三方解決方案。
9. 連接管理器支持多線程應(yīng)用。支持設(shè)置最大連接數(shù),同時支持設(shè)置每個主機(jī)的最大連接數(shù),發(fā)現(xiàn)并關(guān)閉過期的連接。
10. 自動處理Set-Cookie中的Cookie。
11. 插件式的自定義Cookie策略。
12. Request的輸出流可以避免流中內(nèi)容直接緩沖到socket服務(wù)器。
13. Response的輸入流可以有效的從socket服務(wù)器直接讀取相應(yīng)內(nèi)容。
14. 在http1.0和http1.1中利用KeepAlive保持持久連接。
15. 直接獲取服務(wù)器發(fā)送的response code和 headers。
16. 設(shè)置連接超時的能力。
17. 實驗性的支持http1.1 response caching。
18. 源代碼基于Apache License 可免費獲取。
三、使用方法
使用HttpClient發(fā)送請求、接收響應(yīng)很簡單,一般需要如下幾步即可。
1.?創(chuàng)建HttpClient對象。
2.?創(chuàng)建請求方法的實例,并指定請求URL。如果需要發(fā)送GET請求,創(chuàng)建HttpGet對象;如果需要發(fā)送POST請求,創(chuàng)建HttpPost對象。
3.?如果需要發(fā)送請求參數(shù),可調(diào)用HttpGet、HttpPost共同的setParams(HetpParams params)方法來添加請求參數(shù);對于HttpPost對象而言,也可調(diào)用setEntity(HttpEntity entity)方法來設(shè)置請求參數(shù)。
4.?調(diào)用HttpClient對象的execute(HttpUriRequest request)發(fā)送請求,該方法返回一個HttpResponse。
5.?調(diào)用HttpResponse的getAllHeaders()、getHeaders(String name)等方法可獲取服務(wù)器的響應(yīng)頭;調(diào)用HttpResponse的getEntity()方法可獲取HttpEntity對象,該對象包裝了服務(wù)器的響應(yīng)內(nèi)容。程序可通過該對象獲取服務(wù)器的響應(yīng)內(nèi)容。
6.?釋放連接。無論執(zhí)行方法是否成功,都必須釋放連接
四、實例
實例一:模擬get請求發(fā)送,獲取返回的內(nèi)容。
package httpclient;import java.io.IOException;import org.apache.http.HttpEntity; import org.apache.http.client.methods.CloseableHttpResponse; import org.apache.http.client.methods.HttpGet; import org.apache.http.impl.client.CloseableHttpClient; import org.apache.http.impl.client.HttpClients; import org.apache.http.util.EntityUtils;/*** Hello world!**/ public class App {public static void main( String[] args ) throws Exception, IOException{CloseableHttpClient httpclient = HttpClients.createDefault(); //創(chuàng)建httpclientHttpGet httpGet = new HttpGet("https://www.cnblogs.com"); //創(chuàng)建get 請求CloseableHttpResponse response = httpclient.execute(httpGet); //通過httpcleint 發(fā)送get 請求if(response != null){HttpEntity httpentity = response.getEntity(); //獲取響應(yīng)System.out.println(EntityUtils.toString(httpentity,"UTF-8")); //采用工具來將實體進(jìn)行轉(zhuǎn)換輸出 }response.close();httpclient.close();} }?
結(jié)果如下:
?
說明上面代碼采用的maven 項目需要導(dǎo)入httpclient相關(guān)的包,pom文件如下:
<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpclient</artifactId>
<version>4.5.2</version>
</dependency>
總結(jié),上面我看看到httpclient 很容易的模擬了,客戶端發(fā)送了http請求,post方式方式一樣,但是接下來我們看下面的一個實例:
?
package httpclient;import java.io.IOException;import org.apache.http.HttpEntity; import org.apache.http.client.methods.CloseableHttpResponse; import org.apache.http.client.methods.HttpGet; import org.apache.http.impl.client.CloseableHttpClient; import org.apache.http.impl.client.HttpClients; import org.apache.http.util.EntityUtils;/*** Hello world!**/ public class App {public static void main( String[] args ) throws Exception, IOException{CloseableHttpClient httpclient = HttpClients.createDefault(); //創(chuàng)建httpclientHttpGet httpGet = new HttpGet("http://www.tuicool.com/"); //創(chuàng)建get 請求CloseableHttpResponse response = httpclient.execute(httpGet); //通過httpcleint 發(fā)送get 請求if(response != null){HttpEntity httpentity = response.getEntity(); //獲取響應(yīng)System.out.println(EntityUtils.toString(httpentity,"UTF-8")); //采用工具來將實體進(jìn)行轉(zhuǎn)換輸出 }response.close();httpclient.close();} }?
結(jié)果如下:
?
?這是為什么呢? 原因就在于我們上面模擬的是客戶端發(fā)送了http請求,但不是模擬的瀏覽器發(fā)出的請求,因此有些網(wǎng)站做了防護(hù),怎么來模擬瀏覽器發(fā)出的請求呢? 瀏覽器在請的過程中,我們知道會有請求頭信息,以便目標(biāo)服務(wù)器識別,如下:
?
?
?
會有一個:
其中最重要的是就是User-Agent,那么我們要模擬瀏覽器,則需要設(shè)置頭消息,代碼如下:
package httpclient;import java.io.IOException;import org.apache.http.HttpEntity; import org.apache.http.client.methods.CloseableHttpResponse; import org.apache.http.client.methods.HttpGet; import org.apache.http.impl.client.CloseableHttpClient; import org.apache.http.impl.client.HttpClients; import org.apache.http.util.EntityUtils;/*** Hello world!**/ public class App {public static void main( String[] args ) throws Exception, IOException{CloseableHttpClient httpclient = HttpClients.createDefault(); //創(chuàng)建httpclientHttpGet httpGet = new HttpGet("http://www.tuicool.com/"); //創(chuàng)建get 請求httpGet.setHeader("User-Agent", "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/60.0.3112.113 Safari/537.36");CloseableHttpResponse response = httpclient.execute(httpGet); //通過httpcleint 發(fā)送get 請求if(response != null){HttpEntity httpentity = response.getEntity(); //獲取響應(yīng)System.out.println(EntityUtils.toString(httpentity,"UTF-8")); //采用工具來將實體進(jìn)行轉(zhuǎn)換輸出 }response.close();httpclient.close();} }?
這個時候,我們測試一下可以看到結(jié)果如下:
?
結(jié)果已經(jīng)正常顯示出來了,但這個時候,我們是否想到,既然一個瀏覽器發(fā)送了http請求,我們會看到有狀態(tài),那么如何通過httpclient返回的response來獲取對應(yīng)的狀態(tài)呢,以及如何獲取響應(yīng)的類型呢?類型即我們說的content-type
?
這個時候我們需要通過HttpEntity 來獲取,為什么獲取content-type 是因為獲取的類型非常多,有些是不需要我們采集的,這個時候我們可以通過這個內(nèi)容類型進(jìn)行采集過濾。
代碼如下:
package httpclient;import java.io.IOException;import org.apache.http.HttpEntity; import org.apache.http.client.methods.CloseableHttpResponse; import org.apache.http.client.methods.HttpGet; import org.apache.http.impl.client.CloseableHttpClient; import org.apache.http.impl.client.HttpClients; import org.apache.http.util.EntityUtils;/*** Hello world!**/ public class App {public static void main( String[] args ) throws Exception, IOException{CloseableHttpClient httpclient = HttpClients.createDefault(); //創(chuàng)建httpclientHttpGet httpGet = new HttpGet("http://www.tuicool.com/"); //創(chuàng)建get 請求httpGet.setHeader("User-Agent", "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/60.0.3112.113 Safari/537.36");CloseableHttpResponse response = httpclient.execute(httpGet); //通過httpcleint 發(fā)送get 請求if(response != null){System.out.println(response.getStatusLine().getStatusCode());HttpEntity httpentity = response.getEntity(); //獲取響應(yīng) System.out.println(httpentity.getContentType().getValue());//System.out.println(EntityUtils.toString(httpentity,"UTF-8")); //采用工具來將實體進(jìn)行轉(zhuǎn)換輸出 }response.close();httpclient.close();} }結(jié)果如下:
?
總結(jié),上面我們采取的都靜態(tài)的文本等,但是我們采集的時候,如果要采集圖片怎么辦,圖片的獲取處理方式如下:
比如:http://aimg2.tuicool.com/qm6Rre6.jpg!index ?采集這個圖片。
?
package httpclient;import java.io.File; import java.io.IOException; import java.io.InputStream;import org.apache.commons.io.FileUtils; import org.apache.http.HttpEntity; import org.apache.http.client.methods.CloseableHttpResponse; import org.apache.http.client.methods.HttpGet; import org.apache.http.impl.client.CloseableHttpClient; import org.apache.http.impl.client.HttpClients;/*** Hello world!**/ public class App {public static void main( String[] args ) throws Exception, IOException{CloseableHttpClient httpclient = HttpClients.createDefault(); //創(chuàng)建httpclientHttpGet httpGet = new HttpGet("http://aimg2.tuicool.com/qm6Rre6.jpg!index"); //創(chuàng)建get 請求httpGet.setHeader("User-Agent", "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/60.0.3112.113 Safari/537.36");CloseableHttpResponse response = httpclient.execute(httpGet); //通過httpcleint 發(fā)送get 請求if(response != null){//System.out.println(response.getStatusLine().getStatusCode());HttpEntity httpentity = response.getEntity(); //獲取響應(yīng)if(httpentity != null){System.out.println(httpentity.getContentType().getValue()); //判斷內(nèi)容的類型,因為我們要采集圖片,所以要過濾掉其它內(nèi)容.//接著,圖片肯定要通過流的方式去讀取.InputStream inputStream = httpentity.getContent();//然后通過輸入流,然后讀取流,輸出流,則可以轉(zhuǎn)換讀取我們的圖片,流的復(fù)制.//在這里我們可以 通過Apache 提供的IO 工具流來直接進(jìn)行流的復(fù)制.FileUtils.copyToFile(inputStream, new File("D://a.jpg")); //實際中是要拷貝真是的目錄下面,并且圖片的名稱也是唯一的。 }//System.out.println(httpentity.getContentType().getValue());//System.out.println(EntityUtils.toString(httpentity,"UTF-8")); //采用工具來將實體進(jìn)行轉(zhuǎn)換輸出 }response.close();httpclient.close();} }?
注意上面,需要導(dǎo)入io 包。
https://mvnrepository.com/artifact/commons-io/commons-io/2.5
<dependency>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
<version>2.5</version>
</dependency>
?
?
實例二 :上面我們演示了,圖片的采集,和靜態(tài)信息的采集,但是對于一些有防范的網(wǎng)站,一般大公司會有屏蔽信,即不讓你長時間采集,一旦你長時間采集,則會進(jìn)行封掉IP,那這個時候我們該怎么辦,這個時候我們需要代碼IP,先看下面的介紹:
在爬取網(wǎng)頁的時候,有的目標(biāo)站點有反爬蟲機(jī)制,對于頻繁訪問站點以及規(guī)則性訪問站點的行為,會采集屏蔽IP措施。
?
這時候,代理IP就派上用場了。
?
關(guān)于代理IP的話 也分幾種?透明代理、匿名代理、混淆代理、高匿代理
?
1、透明代理(Transparent Proxy)
?
REMOTE_ADDR = Proxy IP
?
HTTP_VIA = Proxy IP
?
HTTP_X_FORWARDED_FOR = Your IP
?
透明代理雖然可以直接“隱藏”你的IP地址,但是還是可以從HTTP_X_FORWARDED_FOR來查到你是誰。
?
2、匿名代理(Anonymous Proxy)
?
REMOTE_ADDR = proxy IP
?
HTTP_VIA = proxy IP
?
HTTP_X_FORWARDED_FOR = proxy IP
?
匿名代理比透明代理進(jìn)步了一點:別人只能知道你用了代理,無法知道你是誰。
?
還有一種比純匿名代理更先進(jìn)一點的:混淆代理,見下節(jié)。
?
3、混淆代理(Distorting Proxies)
?
REMOTE_ADDR = Proxy IP
HTTP_VIA = Proxy IP
HTTP_X_FORWARDED_FOR = Random IP address
?
如上,與匿名代理相同,如果使用了混淆代理,別人還是能知道你在用代理,但是會得到一個假的IP地址,偽裝的更逼真:-)
?
4、高匿代理(Elite proxy或High Anonymity Proxy)
?
REMOTE_ADDR = Proxy IP
?
HTTP_VIA = not determined
?
HTTP_X_FORWARDED_FOR = not determined
?
可以看出來,高匿代理讓別人根本無法發(fā)現(xiàn)你是在用代理,所以是最好的選擇。
?
一般我們搞爬蟲 用的都是 高匿的代理IP;
?
那代理IP 從哪里搞呢 很簡單 ?百度一下,你就知道 一大堆代理IP站點。 ?一般都會給出一些免費的,但是花點錢搞收費接口更加方便;
?
比如?http://www.66ip.cn/
?
httpClient使用代理IP代碼:
package httpclient;import java.io.IOException;import org.apache.http.HttpEntity; import org.apache.http.HttpHost; import org.apache.http.client.config.RequestConfig; import org.apache.http.client.methods.CloseableHttpResponse; import org.apache.http.client.methods.HttpGet; import org.apache.http.impl.client.CloseableHttpClient; import org.apache.http.impl.client.HttpClients; import org.apache.http.util.EntityUtils;/*** Hello world!**/ public class App {public static void main( String[] args ) throws Exception, IOException{CloseableHttpClient httpclient = HttpClients.createDefault(); //創(chuàng)建httpclientHttpGet httpGet = new HttpGet("https://www.taobao.com/"); //創(chuàng)建get 請求HttpHost proxy = new HttpHost("115.202.167.56",808);RequestConfig config = RequestConfig.custom().setProxy(proxy).build();//設(shè)置代理IP httpGet.setConfig(config);httpGet.setHeader("User-Agent", "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/60.0.3112.113 Safari/537.36");CloseableHttpResponse response = httpclient.execute(httpGet); //通過httpcleint 發(fā)送get 請求if(response != null){//System.out.println(response.getStatusLine().getStatusCode());HttpEntity httpentity = response.getEntity(); //獲取響應(yīng)if(httpentity != null){System.out.println(httpentity.getContentType().getValue());System.out.println(EntityUtils.toString(httpentity,"UTF-8")); //采用工具來將實體進(jìn)行轉(zhuǎn)換輸出//System.out.println(httpentity.getContentType().getValue()); //判斷內(nèi)容的類型,因為我們要采集圖片,所以要過濾掉其它內(nèi)容.//接著,圖片肯定要通過流的方式去讀取.//InputStream inputStream = httpentity.getContent();//然后通過輸入流,然后讀取流,輸出流,則可以轉(zhuǎn)換讀取我們的圖片,流的復(fù)制.//在這里我們可以 通過Apache 提供的IO 工具流來直接進(jìn)行流的復(fù)制.//FileUtils.copyToFile(inputStream, new File("D://a.jpg")); //實際中是要拷貝真是的目錄下面,并且圖片的名稱也是唯一的。 }//System.out.println(httpentity.getContentType().getValue());//System.out.println(EntityUtils.toString(httpentity,"UTF-8")); //采用工具來將實體進(jìn)行轉(zhuǎn)換輸出 }response.close();httpclient.close();} }?
通過代理IP,測試結(jié)果如下:
?
其它知識點:
如連接超時時間設(shè)置,讀取內(nèi)容超時時間設(shè)置等。
?
實例三:連接超時和內(nèi)容超時
httpClient在執(zhí)行具體http請求時候 有一個連接的時間和讀取內(nèi)容的時間;
HttpClient連接時間
所謂連接的時候 是HttpClient發(fā)送請求的地方開始到連接上目標(biāo)url主機(jī)地址的時間,理論上是距離越短越快,
線路越通暢越快,但是由于路由復(fù)雜交錯,往往連接上的時間都不固定,運氣不好連不上,HttpClient的默認(rèn)連接時間,據(jù)我測試,
默認(rèn)是1分鐘,假如超過1分鐘 過一會繼續(xù)嘗試連接,這樣會有一個問題 假如遇到一個url老是連不上,會影響其他線程的線程進(jìn)去,說難聽點,
就是蹲著茅坑不拉屎。所以我們有必要進(jìn)行特殊設(shè)置,比如設(shè)置10秒鐘 假如10秒鐘沒有連接上 我們就報錯,這樣我們就可以進(jìn)行業(yè)務(wù)上的處理,
比如我們業(yè)務(wù)上控制 過會再連接試試看。并且這個特殊url寫到log4j日志里去。方便管理員查看。
HttpClient讀取時間
所謂讀取的時間 是HttpClient已經(jīng)連接到了目標(biāo)服務(wù)器,然后進(jìn)行內(nèi)容數(shù)據(jù)的獲取,一般情況 讀取數(shù)據(jù)都是很快速的,
但是假如讀取的數(shù)據(jù)量大,或者是目標(biāo)服務(wù)器本身的問題(比如讀取數(shù)據(jù)庫速度慢,并發(fā)量大等等..)也會影響讀取時間。
同上,我們還是需要來特殊設(shè)置下,比如設(shè)置10秒鐘 假如10秒鐘還沒讀取完,就報錯,同上,我們可以業(yè)務(wù)上處理。
?
HttpClient給我們提供了一個RequestConfig類 專門用于配置參數(shù)比如連接時間,讀取時間以及前面講解的代理IP等。
主要通過:
RequestConfig config=RequestConfig.custom().setConnectTimeout(5000).setSocketTimeout(5000).build();httpGet.setConfig(config);?
?到此,httpclient 相關(guān)的一些基本知識就學(xué)到這里了,如果深入學(xué)習(xí),可以參考httpclient的書籍深入.
?
轉(zhuǎn)載于:https://www.cnblogs.com/pony1223/p/7471464.html
總結(jié)
以上是生活随笔為你收集整理的httpclient 学习的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。