httpclient 学习
Http協議的重要性相信不用我多說了,HttpClient相比傳統JDK自帶的URLConnection,增加了易用性和靈活性,它不僅是客戶端發送Http請求變得容易,而且也方便了開發人員測試接口(基于Http協議的),即提高了開發的效率,也方便提高代碼的健壯性。因此熟練掌握HttpClient是很重要的必修內容,掌握HttpClient后,相信對于Http協議的了解會更加深入。
一、簡介
HttpClient是Apache Jakarta Common下的子項目,用來提供高效的、最新的、功能豐富的支持HTTP協議的客戶端編程工具包,并且它支持HTTP協議最新的版本和建議。HttpClient已經應用在很多的項目中,比如Apache Jakarta上很著名的另外兩個開源項目Cactus和HTMLUnit都使用了HttpClient。
?
二、特性
1. 基于標準、純凈的Java語言。實現了Http1.0和Http1.1
2. 以可擴展的面向對象的結構實現了Http全部的方法(GET, POST, PUT, DELETE, HEAD, OPTIONS, and TRACE)。
3. 支持HTTPS協議。
4. 通過Http代理建立透明的連接。
5. 利用CONNECT方法通過Http代理建立隧道的https連接。
6. Basic, Digest, NTLMv1, NTLMv2, NTLM2 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 可免費獲取。
三、使用方法
使用HttpClient發送請求、接收響應很簡單,一般需要如下幾步即可。
1.?創建HttpClient對象。
2.?創建請求方法的實例,并指定請求URL。如果需要發送GET請求,創建HttpGet對象;如果需要發送POST請求,創建HttpPost對象。
3.?如果需要發送請求參數,可調用HttpGet、HttpPost共同的setParams(HetpParams params)方法來添加請求參數;對于HttpPost對象而言,也可調用setEntity(HttpEntity entity)方法來設置請求參數。
4.?調用HttpClient對象的execute(HttpUriRequest request)發送請求,該方法返回一個HttpResponse。
5.?調用HttpResponse的getAllHeaders()、getHeaders(String name)等方法可獲取服務器的響應頭;調用HttpResponse的getEntity()方法可獲取HttpEntity對象,該對象包裝了服務器的響應內容。程序可通過該對象獲取服務器的響應內容。
6.?釋放連接。無論執行方法是否成功,都必須釋放連接
四、實例
實例一:模擬get請求發送,獲取返回的內容。
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(); //創建httpclientHttpGet httpGet = new HttpGet("https://www.cnblogs.com"); //創建get 請求CloseableHttpResponse response = httpclient.execute(httpGet); //通過httpcleint 發送get 請求if(response != null){HttpEntity httpentity = response.getEntity(); //獲取響應System.out.println(EntityUtils.toString(httpentity,"UTF-8")); //采用工具來將實體進行轉換輸出 }response.close();httpclient.close();} }?
結果如下:
?
說明上面代碼采用的maven 項目需要導入httpclient相關的包,pom文件如下:
<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpclient</artifactId>
<version>4.5.2</version>
</dependency>
總結,上面我看看到httpclient 很容易的模擬了,客戶端發送了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(); //創建httpclientHttpGet httpGet = new HttpGet("http://www.tuicool.com/"); //創建get 請求CloseableHttpResponse response = httpclient.execute(httpGet); //通過httpcleint 發送get 請求if(response != null){HttpEntity httpentity = response.getEntity(); //獲取響應System.out.println(EntityUtils.toString(httpentity,"UTF-8")); //采用工具來將實體進行轉換輸出 }response.close();httpclient.close();} }?
結果如下:
?
?這是為什么呢? 原因就在于我們上面模擬的是客戶端發送了http請求,但不是模擬的瀏覽器發出的請求,因此有些網站做了防護,怎么來模擬瀏覽器發出的請求呢? 瀏覽器在請的過程中,我們知道會有請求頭信息,以便目標服務器識別,如下:
?
?
?
會有一個:
其中最重要的是就是User-Agent,那么我們要模擬瀏覽器,則需要設置頭消息,代碼如下:
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(); //創建httpclientHttpGet httpGet = new HttpGet("http://www.tuicool.com/"); //創建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 發送get 請求if(response != null){HttpEntity httpentity = response.getEntity(); //獲取響應System.out.println(EntityUtils.toString(httpentity,"UTF-8")); //采用工具來將實體進行轉換輸出 }response.close();httpclient.close();} }?
這個時候,我們測試一下可以看到結果如下:
?
結果已經正常顯示出來了,但這個時候,我們是否想到,既然一個瀏覽器發送了http請求,我們會看到有狀態,那么如何通過httpclient返回的response來獲取對應的狀態呢,以及如何獲取響應的類型呢?類型即我們說的content-type
?
這個時候我們需要通過HttpEntity 來獲取,為什么獲取content-type 是因為獲取的類型非常多,有些是不需要我們采集的,這個時候我們可以通過這個內容類型進行采集過濾。
代碼如下:
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(); //創建httpclientHttpGet httpGet = new HttpGet("http://www.tuicool.com/"); //創建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 發送get 請求if(response != null){System.out.println(response.getStatusLine().getStatusCode());HttpEntity httpentity = response.getEntity(); //獲取響應 System.out.println(httpentity.getContentType().getValue());//System.out.println(EntityUtils.toString(httpentity,"UTF-8")); //采用工具來將實體進行轉換輸出 }response.close();httpclient.close();} }結果如下:
?
總結,上面我們采取的都靜態的文本等,但是我們采集的時候,如果要采集圖片怎么辦,圖片的獲取處理方式如下:
比如: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(); //創建httpclientHttpGet httpGet = new HttpGet("http://aimg2.tuicool.com/qm6Rre6.jpg!index"); //創建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 發送get 請求if(response != null){//System.out.println(response.getStatusLine().getStatusCode());HttpEntity httpentity = response.getEntity(); //獲取響應if(httpentity != null){System.out.println(httpentity.getContentType().getValue()); //判斷內容的類型,因為我們要采集圖片,所以要過濾掉其它內容.//接著,圖片肯定要通過流的方式去讀取.InputStream inputStream = httpentity.getContent();//然后通過輸入流,然后讀取流,輸出流,則可以轉換讀取我們的圖片,流的復制.//在這里我們可以 通過Apache 提供的IO 工具流來直接進行流的復制.FileUtils.copyToFile(inputStream, new File("D://a.jpg")); //實際中是要拷貝真是的目錄下面,并且圖片的名稱也是唯一的。 }//System.out.println(httpentity.getContentType().getValue());//System.out.println(EntityUtils.toString(httpentity,"UTF-8")); //采用工具來將實體進行轉換輸出 }response.close();httpclient.close();} }?
注意上面,需要導入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>
?
?
實例二 :上面我們演示了,圖片的采集,和靜態信息的采集,但是對于一些有防范的網站,一般大公司會有屏蔽信,即不讓你長時間采集,一旦你長時間采集,則會進行封掉IP,那這個時候我們該怎么辦,這個時候我們需要代碼IP,先看下面的介紹:
在爬取網頁的時候,有的目標站點有反爬蟲機制,對于頻繁訪問站點以及規則性訪問站點的行為,會采集屏蔽IP措施。
?
這時候,代理IP就派上用場了。
?
關于代理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
?
匿名代理比透明代理進步了一點:別人只能知道你用了代理,無法知道你是誰。
?
還有一種比純匿名代理更先進一點的:混淆代理,見下節。
?
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
?
可以看出來,高匿代理讓別人根本無法發現你是在用代理,所以是最好的選擇。
?
一般我們搞爬蟲 用的都是 高匿的代理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(); //創建httpclientHttpGet httpGet = new HttpGet("https://www.taobao.com/"); //創建get 請求HttpHost proxy = new HttpHost("115.202.167.56",808);RequestConfig config = RequestConfig.custom().setProxy(proxy).build();//設置代理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 發送get 請求if(response != null){//System.out.println(response.getStatusLine().getStatusCode());HttpEntity httpentity = response.getEntity(); //獲取響應if(httpentity != null){System.out.println(httpentity.getContentType().getValue());System.out.println(EntityUtils.toString(httpentity,"UTF-8")); //采用工具來將實體進行轉換輸出//System.out.println(httpentity.getContentType().getValue()); //判斷內容的類型,因為我們要采集圖片,所以要過濾掉其它內容.//接著,圖片肯定要通過流的方式去讀取.//InputStream inputStream = httpentity.getContent();//然后通過輸入流,然后讀取流,輸出流,則可以轉換讀取我們的圖片,流的復制.//在這里我們可以 通過Apache 提供的IO 工具流來直接進行流的復制.//FileUtils.copyToFile(inputStream, new File("D://a.jpg")); //實際中是要拷貝真是的目錄下面,并且圖片的名稱也是唯一的。 }//System.out.println(httpentity.getContentType().getValue());//System.out.println(EntityUtils.toString(httpentity,"UTF-8")); //采用工具來將實體進行轉換輸出 }response.close();httpclient.close();} }?
通過代理IP,測試結果如下:
?
其它知識點:
如連接超時時間設置,讀取內容超時時間設置等。
?
實例三:連接超時和內容超時
httpClient在執行具體http請求時候 有一個連接的時間和讀取內容的時間;
HttpClient連接時間
所謂連接的時候 是HttpClient發送請求的地方開始到連接上目標url主機地址的時間,理論上是距離越短越快,
線路越通暢越快,但是由于路由復雜交錯,往往連接上的時間都不固定,運氣不好連不上,HttpClient的默認連接時間,據我測試,
默認是1分鐘,假如超過1分鐘 過一會繼續嘗試連接,這樣會有一個問題 假如遇到一個url老是連不上,會影響其他線程的線程進去,說難聽點,
就是蹲著茅坑不拉屎。所以我們有必要進行特殊設置,比如設置10秒鐘 假如10秒鐘沒有連接上 我們就報錯,這樣我們就可以進行業務上的處理,
比如我們業務上控制 過會再連接試試看。并且這個特殊url寫到log4j日志里去。方便管理員查看。
HttpClient讀取時間
所謂讀取的時間 是HttpClient已經連接到了目標服務器,然后進行內容數據的獲取,一般情況 讀取數據都是很快速的,
但是假如讀取的數據量大,或者是目標服務器本身的問題(比如讀取數據庫速度慢,并發量大等等..)也會影響讀取時間。
同上,我們還是需要來特殊設置下,比如設置10秒鐘 假如10秒鐘還沒讀取完,就報錯,同上,我們可以業務上處理。
?
HttpClient給我們提供了一個RequestConfig類 專門用于配置參數比如連接時間,讀取時間以及前面講解的代理IP等。
主要通過:
RequestConfig config=RequestConfig.custom().setConnectTimeout(5000).setSocketTimeout(5000).build();httpGet.setConfig(config);?
?到此,httpclient 相關的一些基本知識就學到這里了,如果深入學習,可以參考httpclient的書籍深入.
?
轉載于:https://www.cnblogs.com/pony1223/p/7471464.html
總結
以上是生活随笔為你收集整理的httpclient 学习的全部內容,希望文章能夠幫你解決所遇到的問題。