http協議能夠說是如今Internet上面最重要,使用最多的協議之一了,愈來愈多的java應用須要使用http協議來訪問網絡資源,特別是如今rest api的流行,HttpClient 是 Apache Jakarta Common 下的子項目,用來提供高效的、最新的、功能豐富的支持 HTTP 協議的客戶端編程工具包,而且它支持 HTTP 協議最新的版本和建議。HttpClient 已經應用在不少的項目中,好比 Apache Jakarta 上很著名的另外兩個開源項目 Cactus 和 HTMLUnit 都使用了 HttpClient,不少的java的爬蟲也是經過HttpClient實現的,研究HttpClient對咱們來講是很是重要的。javascript
不少人以爲既然HttpClient是一個HTTP客戶端編程工具,不少人把他當作瀏覽器來理解,可是其實HttpClient不是瀏覽器,它是一個HTTP通訊庫,所以它只提供一個通用瀏覽器應用程序所指望的功能子集,最根本的區別是HttpClient中沒有用戶界面,瀏覽器須要一個渲染引擎來顯示頁面,並解釋用戶輸入,例如鼠標點擊顯示頁面上的某處,有一個佈局引擎,計算如何顯示HTML頁面,包括級聯樣式表和圖像。javascript解釋器運行嵌入HTML頁面或從HTML頁面引用的javascript代碼。來自用戶界面的事件被傳遞到javascript解釋器進行處理。除此以外,還有用於插件的接口,能夠處理Applet,嵌入式媒體對象(如pdf文件,Quicktime電影和Flash動畫)或ActiveX控件(能夠執行任何操做)。HttpClient只能以編程的方式經過其API用於傳輸和接受HTTP消息。HttpClient也是徹底內容不可知的。html
另外一個主要區別是對錯誤輸入或HTTP標準違規的容忍。 須要容許無效的用戶輸入,以使瀏覽器用戶友好。 還須要對從服務器檢索的畸形文檔的容忍度,以及在執行協議時服務器行爲的缺陷,使盡量多的用戶可訪問的網站。 然而,HttpClient努力在默認狀況下儘量接近並遵照HTTP標準規範和相關標準。 它還提供了一些手段來放鬆規範所施加的一些限制,這些限制容許或要求與不兼容的HTTP源或代理服務器兼容。java
注意這個版本主要是基於HttpClient4.5.2版本的來說解的,也是如今最新的版本,之因此要提供版本說明的是由於HttpClient 3版本和HttpClient 4版本差異仍是不少大的,基本HttpClient裏面的接口都變了,你把HttpClient 3版本的代碼拿到HttpClient 4上面都運行不起來,會報錯的。因此這兒必定要注意,好了廢話很少說了,開始。apache
//httpclient的接口基本都在這兒 <dependency> <groupId>org.apache.httpcomponents</groupId> <artifactId>httpclient</artifactId> <version>4.5.2</version> </dependency> //httpclient緩存 <dependency> <groupId>org.apache.httpcomponents</groupId> <artifactId>httpclient-cache</artifactId> <version>4.5</version> </dependency> //http的mime類型都在這裏面 <dependency> <groupId>org.apache.httpcomponents</groupId> <artifactId>httpmime</artifactId> <version>4.3.2</version> </dependency>
注意:常見的MIME類型(通用型):編程
超文本標記語言文本 .html text/htmlapi
xml文檔 .xml text/xml瀏覽器
XHTML文檔 .xhtml application/xhtml+xml緩存
普通文本 .txt text/plain服務器
RTF文本 .rtf application/rtf網絡
PDF文檔 .pdf application/pdf
Microsoft Word文件 .word application/msword
PNG圖像 .png image/png
GIF圖形 .gif image/gif
JPEG圖形 .jpeg,.jpg image/jpeg
au聲音文件 .au audio/basic
MIDI音樂文件 mid,.midi audio/midi,audio/x-midi
RealAudio音樂文件 .ra, .ram audio/x-pn-realaudio
MPEG文件 .mpg,.mpeg video/mpeg
AVI文件 .avi video/x-msvideo
TAR文件 .tar application/x-tar
任意的二進制數據 application/octet-stream
先直接貼代碼:
package fangdd.HttpClientDemo; import java.io.BufferedReader; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.util.Locale; import org.apache.http.HttpEntity; import org.apache.http.client.HttpClient; 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; public class HttpGetNewSample { public static void main(String[] args) { // TODO Auto-generated method stub String url="http://www.baidu.com"; //1.使用默認的配置的httpclient CloseableHttpClient client = HttpClients.createDefault(); //2.使用get方法 HttpGet httpGet = new HttpGet(url); InputStream inputStream = null; CloseableHttpResponse response = null; try { //3.執行請求,獲取響應 response = client.execute(httpGet); //看請求是否成功,這兒打印的是http狀態碼 System.out.println(response.getStatusLine().getStatusCode()); //4.獲取響應的實體內容,就是咱們所要抓取得網頁內容 HttpEntity entity = response.getEntity(); //5.將其打印到控制檯上面 //方法一:使用EntityUtils if (entity != null) { System.out.println(EntityUtils.toString(entity, "utf-8")); } EntityUtils.consume(entity); //方法二 :使用inputStream /* if (entity != null) { inputStream = entity.getContent(); BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(inputStream)); String line = ""; while ((line = bufferedReader.readLine()) != null) { System.out.println(line); } }*/ } catch (UnsupportedOperationException | IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } finally { if (inputStream != null) { try { inputStream.close(); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } } if (response != null) { try { response.close(); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } } } } }
其實從上面咱們就能夠總結出使用HttpClient其實分爲6個步驟
1.建立HttpClient對象
這兒使用的是org.apache.http.impl.client.CloseableHttpClient,他是HttpClient接口的一個實例,建立該對象的最簡單方法是CloseableHttpClient client = HttpClients.createDefault();
HttpClients是建立CloseableHttpClient的工廠,採用默認的配置來建立實例,通常狀況下咱們就用這個默認的實例就足夠,後面咱們能夠去看下怎麼定製本身需求配置的來建立HttpClient接口的實例。若是你去看這個函數的源代碼,你能夠看到org.apache.http.client.CookieStore,org.apache.http.client.config.RequestConfig等等都是採用默認的。後面咱們會專門有篇博客探討怎麼根據本身的需求定製httpclient。
2.建立某種請求方法的實例。
建立某種請求的實例,並指定請求的url,若是是get請求,建立對象HttpGet,若是是post 請求,建立對象HttpPost。類型的還有 HttpHead, HttpPost, HttpPut, HttpDelete, HttpTrace, 還有 HttpOptions。分別對應HEAD、POST PUT、DELETE、TRACE、OPTIONS方法,每一個方法是作什麼的以下表:
方法 | 描述 | 是否包含主體 |
GET | 從服務器獲取一份文檔 | 否 |
HEAD | 只從服務器獲取文檔的首部 | 否 |
POST | 向服務器發送須要處理的數據 | 是 |
PUT | 將請求的主體部分存儲在服務器上 | 是 |
TRACE | 對可能通過代理服務器傳送到服務器上去的報文進行追蹤 | 否 |
OPTIONS | 決定能夠在服務器上執行哪些方法 | 否 |
DELETE | 從服務器上刪除一份文檔 | 否 |
能夠看獲得在Http協議中,只有post方法和put方法的請求裏面有實體
3.若是有請求參數的話,Get方法直接寫在url後面,例如
HttpGet httpget = new HttpGet( 「http://www.google.com/search?hl=zh-CN&q=httpclient&btnG=Google+Search&aq=f&oq=」); 或者使用setParameter來設置參數 URI uri = new URIBuilder() .setScheme(「http」) .setHost(「www.google.com」) .setPath(「/ search」) .setParameter(「q」,「httpclient」) .setParameter(「btnG」,「Google搜索」) .setParameter(「aq」,「f」) .setParameter(「oq」,「」) 。創建(); HttpGet httpget = new HttpGet(uri); System.out.println(httpget.getURI()); stdout> http://www.google.com/search?q=httpclient&btnG=Google+Search&aq=f&oq= post方法用setEntity(HttpEntity entity)方法來設置請求參數。 後面會詳細的探討Entity這個東西,這兒就不在贅敘。
4.發送請求。
調用CloseableHttpClient對象的execute(HttpUriRequest request)發送請求,該方法返回一個CloseableHttpResponse對象。 CloseableHttpResponse response = client.execute(post);,很明顯CloseableHttpResponse就是用了處理返回數據的實體,經過它咱們能夠拿到返回的狀態碼、首部、實體等等咱們須要的東西。
5.獲取請求結果。
調用CloseableHttpResponse的getAllHeaders()、getHeaders(String name)等方法可獲取服務器的響應頭;調用CloseableHttpResponse的getEntity()方法可獲取HttpEntity對象,該對象包裝了服務器的響應內容。程序可經過該對象獲取服務器的響應內容。
HttpEntity entity = response.getEntity(); //5.將其打印到顯示器上面 //方法一:使用EntityUtils /* if(entity!=null) { System.out.println(EntityUtils.toString(entity,"utf-8")); } EntityUtils.consume(entity) */ //方法二 InputStream inputStream = entity.getContent(); BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(inputStream)); String line = ""; while ((line = bufferedReader.readLine()) != null) { System.out.println(line); }
經過CloseableHttpEntity的getEntity取得實體以後,有兩種處理結果的方法,
方法一:使用EntityUtils來處理。
該類是官方提供的一個處理實體的工具類,toSting方法將返回的實體轉換爲字符串,可是官網不建議使用這個,除非響應實體從一個可信HTTP服務器發起和已知是有限長度的。
方法二:使用InputStream來讀取
由於httpEntity.getContent方法返回的就是InputStream類型。這種方法是官網推薦的方式,須要記得的是要本身釋放底層資源。
6.關閉鏈接,釋放資源。
若是是使用EntityUtils來處理實體的使用 EntityUtils.consume(entity)來釋放資源,能夠看獲得該函數源碼爲:
public static void consume(final HttpEntity entity) throws IOException { if (entity == null) { return; } if (entity.isStreaming()) { final InputStream instream = entity.getContent(); if (instream != null) { instream.close(); } } }
其實仍是經過關閉inputStream,而後最後咱們再關閉CloseableHttpResponse就能夠了
若是是使用InputStream來處理實體的,釋放代碼以下
CloseableHttpClient httpclient = HttpClients.createDefault(); HttpGet httpget = new HttpGet(「http:// localhost /」); CloseableHttpResponse response = httpclient.execute(httpget); try{ HttpEntity entity = response.getEntity(); if(entity!= null){ InputStream instream = entity.getContent(); try{ //作一些有用的事情 } finally { intream.close(); }} }} } finally { response.close(); }}
關閉內容流和關閉響應之間的區別是:前者將嘗試經過消耗實體內容來保持底層鏈接活動,然後者當即關閉並丟棄鏈接