HttpClient基礎(chǔ)解析
本文講述了HttpClient基礎(chǔ)知識,對相關(guān)概念進行解釋在這里分享給大家,供大家參考。
1. 請求執(zhí)行:
HttpClient最重要的功能是執(zhí)行HTTP方法。執(zhí)行HTTP方法涉及一個或多個HTTP請求/ HTTP響應交換,通常由HttpClient內(nèi)部處理。用戶期望提供一個請求對象來執(zhí)行,并且希望HttpClient將請求發(fā)送到目標服務器返回相應的響應對象,如果執(zhí)行失敗則拋出異常。
很自然,HttpClient API的主要入口點是定義上述合同的HttpClient接口。
這是一個請求執(zhí)行過程的一個例子,它的最簡單的形式是:
CloseableHttpClient httpclient = HttpClients.createDefault();
HttpGet httpget = new HttpGet("https://localhost/");
CloseableHttpResponse response = httpclient.execute(httpget);
try {
<...>
} finally {
response.close();
}
1.1. HTTP請求
所有HTTP請求都有一個請求行,包括方法名稱,請求URI和HTTP協(xié)議版本。
HttpClient的支持了在HTTP / 1.1規(guī)范中定義的所有HTTP方法的框的:GET,HEAD, POST,PUT,DELETE, TRACE和OPTIONS。沒有為每個方法類型:一個特定的類HttpGet, HttpHead,HttpPost, HttpPut,HttpDelete, HttpTrace,和HttpOptions。
Request-URI是統(tǒng)一資源標識符,用于標識應用請求的資源。HTTP請求URI由協(xié)議方案,主機名,可選端口,資源路徑,可選查詢和可選片段組成。
URI uri = new URIBuilder()
.setScheme("http")
.setHost("www.google.com")
.setPath("/search")
.setParameter("q", "httpclient")
.setParameter("btnG", "Google Search")
.setParameter("aq", "f")
.setParameter("oq", "")
.build();
HttpGet httpget = new HttpGet(uri);
System.out.println(httpget.getURI());
1.2. HTTP響應
HTTP響應是在接收和解釋請求消息之后由服務器發(fā)送回客戶端的消息。該消息的第一行包括協(xié)議版本,后跟數(shù)字狀態(tài)代碼及其關(guān)聯(lián)的文本短語。
HttpResponse response = new BasicHttpResponse(HttpVersion.HTTP_1_1, HttpStatus.SC_OK, "OK"); System.out.println(response.getProtocolVersion()); System.out.println(response.getStatusLine().getStatusCode()); System.out.println(response.getStatusLine().getReasonPhrase()); System.out.println(response.getStatusLine().toString()); //輸出結(jié)果 /* HTTP/1.1 200 OK HTTP/1.1 200 OK */
1.3. 處理消息頭
HTTP消息可以包含描述消息屬性的多個頭部,如內(nèi)容長度,內(nèi)容類型等。HttpClient提供了檢索,添加,刪除和枚舉頭文件的方法。
獲取給定類型的所有標頭的最有效的方法是使用 HeaderIterator接口。
HttpResponse response = new BasicHttpResponse(HttpVersion.HTTP_1_1,HttpStatus.SC_OK
,"OK");
response.addHeader("Set-Cookie",
"c1 = a; path = /; domain = localhost");
response.addHeader("Set-Cookie",
"c2 = b; path = \"/ \",c3 = c; domain = \"localhost \"");
HeaderIterator it = response.headerIterator("Set-Cookie");
while(it.hasNext()){
System.out.println(it.next());
}
它還提供了方便的方法來將HTTP消息解析為單獨的頭元素。
HttpResponse response = new BasicHttpResponse(HttpVersion.HTTP_1_1,HttpStatus.SC_OK
,"OK");
response.addHeader("Set-Cookie",
"c1 = a; path = /; domain = localhost");
response.addHeader("Set-Cookie",
"c2 = b; path = \"/ \",c3 = c; domain = \"localhost \"");
HeaderElementIterator it = new BasicHeaderElementIterator(
response.headerIterator("Set-Cookie"));
while(it.hasNext()){
HeaderElement elem = it.nextElement();
System.out.println(elem.getName()+"="+ elem.getValue());
NameValuePair [] params = elem.getParameters();
for(int i = 0; i <params.length; i ++){
System.out。println(""+ params [i]);
}
}
1.4. HTTP實體
HTTP消息可以攜帶與請求或響應相關(guān)聯(lián)的內(nèi)容實體。實體可以在一些請求和一些響應中找到,因為它們是可選的。使用實體的請求被稱為實體封裝請求。HTTP規(guī)范定義了兩個實體封裝請求方法:POST和 PUT。響應通常期望包含內(nèi)容實體。有例外的情況,如應對 HEAD方法204 No Content, 304 Not Modified,205 Reset Content 響應。
HttpClient根據(jù)其內(nèi)容來源區(qū)分三種實體:
streamed: 內(nèi)容是從流中接收的,或者即時生成的。特別地,該類別包括從HTTP響應接收到的實體。流式實體通常不可重復。
self-contained: 內(nèi)容在內(nèi)存中或通過獨立于連接或其他實體的方式獲取。自包含的實體通常是可重復的。這種類型的實體將主要用于封閉HTTP請求的實體。
wrapping: 內(nèi)容是從另一個實體獲得的。
當從HTTP響應流出內(nèi)容時,此區(qū)別對于連接管理很重要。對于由應用程序創(chuàng)建并且僅使用HttpClient發(fā)送的請求實體,流和獨立的區(qū)別不重要。在這種情況下,建議將不可重復的實體視為流式傳輸,將可重復的實體視為獨立的。
1.4.1. 可重復的實體
實體可以是可重復的,這意味著它的內(nèi)容可以被讀取不止一次。這是唯一可能的自包含的實體(像 ByteArrayEntity或 StringEntity)
1.4.2. 使用HTTP實體
由于實體可以表示二進制和字符內(nèi)容,它支持字符編碼(以支持后者,即字符內(nèi)容)。
當執(zhí)行帶有封閉內(nèi)容的請求時,或者當請求成功并且使用響應主體將結(jié)果發(fā)送回客戶端時,實體被創(chuàng)建。
要從實體讀取內(nèi)容,可以通過HttpEntity.getContent()方法來檢索輸入流,該方法返回一個java.io.InputStream,或者可以向HttpEntity.writeTo(OutputStream)方法提供輸出流,一旦所有內(nèi)容已寫入給定流,該方法將返回。
當實體已經(jīng)接收到傳入消息時,方法 HttpEntity.getContentType()和 HttpEntity.getContentLength()方法可用于讀取公共元數(shù)據(jù),如頭Content-Type和 Content-Length頭(如果可用)。由于 Content-Type標題可以包含text / plain或text / html等文本MIME類型的字符編碼,因此該 HttpEntity.getContentEncoding()方法用于讀取此信息。如果標題不可用,則返回長度為-1,內(nèi)容類型為NULL。如果Content-Type 標題可用,Header將返回一個對象。
當為外發(fā)消息創(chuàng)建實體時,該元數(shù)據(jù)必須由實體的創(chuàng)建者提供。
StringEntity myEntity = new StringEntity("important message",
ContentType.create("text/plain", "UTF-8"));
System.out.println(myEntity.getContentType());
System.out.println(myEntity.getContentLength());
System.out.println(EntityUtils.toString(myEntity));
System.out.println(EntityUtils.toByteArray(myEntity).length);
1.5. 確保發(fā)布低級別資源
為了確保系統(tǒng)資源的正確釋放,必須關(guān)閉與實體或響應本身相關(guān)聯(lián)的內(nèi)容流
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 {
instream.close();
}
}
} finally {
response.close();
}
關(guān)閉內(nèi)容流和關(guān)閉響應之間的區(qū)別在于,前者將嘗試通過占用實體內(nèi)容來保持底層連接,而后者會立即關(guān)閉并放棄連接。
請注意,HttpEntity.writeTo(OutputStream) 一旦實體完全寫出,還需要確保正確釋放系統(tǒng)資源的方法。如果此方法獲取一個java.io.InputStream通過調(diào)用 的實例 HttpEntity.getContent(),那么也希望在finally子句中關(guān)閉流。
當使用流實體時,可以使用該 EntityUtils.consume(HttpEntity)方法來確保實體內(nèi)容已被完全消耗,底層流已經(jīng)被關(guān)閉。
然而,可能會有情況,當只需要檢索整個響應內(nèi)容的一小部分時,消耗剩余內(nèi)容并使連接可重用的性能損失太高,在這種情況下,可以通過關(guān)閉終止內(nèi)容流響應。
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();
int byteOne = instream.read();
int byteTwo = instream.read();
//不需要休息
}
} finally {
response.close();
}
連接不會重復使用,但由其持有的所有級別資源將被正確地分配。
1.6. 消費實體內(nèi)容
消費實體內(nèi)容的推薦方法是使用它 HttpEntity.getContent()或 HttpEntity.writeTo(OutputStream)方法。HttpClient還附帶了EntityUtils類,它暴露了幾種靜態(tài)方法,以便更容易地從實體讀取內(nèi)容或信息。java.io.InputStream可以使用這個類的方法,而不是直接讀取,而不是直接讀取字符串/字節(jié)數(shù)組中的整個內(nèi)容正文。但是,EntityUtils除非響應實體來自可信HTTP服務器,而且已知其長度有限,否則強烈建議不要使用此功能。
CloseableHttpClient httpclient = HttpClients.createDefault();
HttpGet httpget = new HttpGet("http:// localhost /");
CloseableHttpResponse response = httpclient.execute(httpget);
try{
HttpEntity entity = response.getEntity();
if(entity!= null){
long len = entity.getContentLength();
if(len!= -1 && len <2048){
System.out.println(EntityUtils.toString(entity));
} else {
// Stream content out
}
}
} finally {
response.close();
}
在某些情況下,可能需要多次讀取實體內(nèi)容。在這種情況下,實體內(nèi)容必須以某種方式緩存,無論是在內(nèi)存還是在磁盤上。最簡單的方法是通過用BufferedHttpEntity類包裝原始實體。這將導致將原始實體的內(nèi)容讀入內(nèi)存緩沖區(qū)。在所有其他方面,實體包裝器將具有原始包裝器。
CloseableHttpResponse response = <...>
HttpEntity entity = response.getEntity();
if(entity!= null){
entity = new BufferedHttpEntity(entity);
}
1.7. 制作實體內(nèi)容
HttpClient提供了幾個類,可以通過HTTP連接高效地流出內(nèi)容。這些類的實例可以與實體包圍請求,如相關(guān)聯(lián)POST并PUT 以包圍實體內(nèi)容分成傳出HTTP請求。HttpClient的提供了幾個類為最常見的數(shù)據(jù)的容器,如字符串,字節(jié)數(shù)組,輸入流,和文件:StringEntity, ByteArrayEntity, InputStreamEntity,和 FileEntity。
File file = new File("somefile.txt");
FileEntity entity = new FileEntity(file,
ContentType.create("text / plain","UTF-8"));
HttpPost httppost = new HttpPost("http://localhost/action.do");
httppost.setEntity(entity);
1.7.1 HTML表單
許多應用程序需要模擬提交HTML表單的過程,例如,以登錄到Web應用程序或提交輸入數(shù)據(jù)。HttpClient提供實體類 UrlEncodedFormEntity來促進進程。
List <NameValuePair> formparams = new ArrayList <NameValuePair>();
formparams.add(new BasicNameValuePair("param1","value1"));
formparams.add(new BasicNameValuePair("param2","value2"));
UrlEncodedFormEntity entity = new UrlEncodedFormEntity(formparams,Consts.UTF_8);
HttpPost httppost = new HttpPost("http://localhost/handler.do");
httppost.setEntity(entity);
該UrlEncodedFormEntity實例將使用所謂的URL編碼來對參數(shù)進行編碼并產(chǎn)生以下內(nèi)容:
param1=value1¶m2=value2
1.7.2. 內(nèi)容分塊
一般建議讓HttpClient根據(jù)正在傳輸?shù)腍TTP消息的屬性選擇最合適的傳輸編碼。然而,可以通知HttpClient,通過設(shè)置HttpEntity.setChunked()為true,優(yōu)先選擇塊編碼。請注意,HttpClient只會使用此標志作為提示。當使用不支持塊編碼的HTTP協(xié)議版本(如HTTP / 1.0)時,此值將被忽略。
StringEntity entity = new StringEntity("important message",
ContentType.create("plain / text",Consts.UTF_8));
entity.setChunked(true);
HttpPost httppost = new HttpPost("http://localhost/acrtion.do");
httppost.setEntity(entity);
1.8. 響應處理程序
處理響應的最簡單和最方便的方法是使用ResponseHandler包含該handleResponse(HttpResponse response)方法的界面。這種方法完全可以緩解用戶不必擔心連接管理。使用ResponseHandlerHttpClient 時 ,無論請求執(zhí)行是成功還是導致異常,HttpClient都會自動保證將連接釋放回連接管理器。
CloseableHttpClient httpclient = HttpClients.createDefault();
HttpGet httpget = new HttpGet("http://localhost/json");
ResponseHandler<MyJsonObject> rh = new ResponseHandler<MyJsonObject>() {
@Override
public JsonObject handleResponse(
final HttpResponse response) throws IOException {
StatusLine statusLine = response.getStatusLine();
HttpEntity entity = response.getEntity();
if (statusLine.getStatusCode() >= 300) {
throw new HttpResponseException(
statusLine.getStatusCode(),
statusLine.getReasonPhrase());
}
if (entity == null) {
throw new ClientProtocolException("Response contains no content");
}
Gson gson = new GsonBuilder().create();
ContentType contentType = ContentType.getOrDefault(entity);
Charset charset = contentType.getCharset();
Reader reader = new InputStreamReader(entity.getContent(), charset);
return gson.fromJson(reader, MyJsonObject.class);
}
};
MyJsonObject myjson = client.execute(httpget, rh);
總結(jié)
以上是本文對HttpClient基礎(chǔ)知識的全部介紹,希望對大家有所幫助。
相關(guān)文章
java 集合之實現(xiàn)類ArrayList和LinkedList的方法
下面小編就為大家?guī)硪黄猨ava 集合之實現(xiàn)類ArrayList和LinkedList的方法。小編覺得挺不錯的,現(xiàn)在就分享給大家,也給大家做個參考。一起跟隨小編過來看看吧2017-10-10
Java中Iterator與ListIterator迭代的區(qū)別
本文主要介紹了Java中Iterator與ListIterator迭代的區(qū)別,文中通過示例代碼介紹的非常詳細,需要的朋友們下面隨著小編來一起學習學習吧2021-07-07
Java的this關(guān)鍵字的使用與方法的重載相關(guān)知識
這篇文章主要介紹了Java的this關(guān)鍵字的使用與方法的重載相關(guān)知識,是Java入門學習中的基礎(chǔ)知識,需要的朋友可以參考下2015-09-09
maven-maven使用-P參數(shù)打包不同環(huán)境問題
這篇文章主要介紹了maven-maven使用-P參數(shù)打包不同環(huán)境問題,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教2023-11-11
關(guān)于SpringBoot配置文件application.properties的路徑問題
這篇文章主要介紹了關(guān)于SpringBoot配置文件application.properties的路徑問題,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2022-08-08
多數(shù)據(jù)源模式JPA整合sharding-jdbc實現(xiàn)數(shù)據(jù)脫敏
這篇文章主要為大家介紹了JPA項目中多數(shù)據(jù)源模式整合sharding-jdbc來實現(xiàn)數(shù)據(jù)脫敏,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步2022-02-02
解決spring cloud zuul與nginx的域名轉(zhuǎn)發(fā)問題
這篇文章主要介紹了spring cloud zuul與nginx的域名轉(zhuǎn)發(fā)問題,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2021-07-07

