《HttpClient官方文檔》1.1 執行請求

杜老師說 2022-01-07 05:51:27 阅读数:488

httpclient 官方

原文鏈接

1.1. 執行請求

HttpClient最基本的功能就是執行HTTP方法。 一個HTTP方法的執行包含一次或多次HTTP請求與響應,通常由HttpClient的內部處理。
用戶提供一個請求對象,HttpClient發送該請求到目標服務器,服務器返回相應的響應對象,如果執行未成功則拋出一個异常。

很自然地,HttpClient的API的主要入口點就是定義了上述協議的HttpClient接口。下面是一個最簡單的請求執行過程例子

CloseableHttpClient httpclient = HttpClients.createDefault();HttpGet httpget = new HttpGet("http://localhost/");CloseableHttpResponse response = httpclient.execute(httpget);try { <...>} finally { response.close();}

1.1.1. HTTP 請求

所有HTTP請求都有由方法名,請求URI和HTTP協議版本組成的請求行。

HttpClient支持開箱即用HTTP/1.1規範中定義的所有HTTP方法:GET, HEAD,POST, PUT, DELETE,TRACE and OPTIONS。它們都有一個特定的類對應這些方法類型: HttpGet,HttpHead, HttpPost,HttpPut, HttpDelete,HttpTrace, and HttpOptions.

請求的URI是統一資源定比特符,它標識了應用於哪個請求之上的資源。HTTP請求的URI包含協議方案,主機名,可選的端口,資源路徑,可選查詢和可選片段。

HttpGet httpget = new HttpGet( "http://www.google.com/search?hl=en&q=httpclient&btnG=Google+Search&aq=f&oq=");

HttpClient 提供 URIBuilder 實用類來簡化請求 URL的創建和修改.

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());

輸出內容為 >

http://www.google.com/search?q=httpclient&btnG=Google+Search&aq=f&oq=

1.1.2. HTTP 響應

HTTP響應是服務器端在接收和解釋客戶端請求消息後,返回客戶端的消息。該消息的第一行包含協議版本以及後面跟著的數字形式的狀態代碼和相關的文本段。

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());

輸出內容為 >

HTTP/1.1200OKHTTP/1.1 200 OK

1.1.3. 消息頭

HTTP消息可以包含多個描述該消息屬性的頭部諸如內容長度,內容類型等,HttpClient的提供方法來檢索,添加,删除和枚舉這些頭部。

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\"");Header h1 = response.getFirstHeader("Set-Cookie");System.out.println(h1);Header h2 = response.getLastHeader("Set-Cookie");System.out.println(h2);Header[] hs = response.getHeaders("Set-Cookie");System.out.println(hs.length);

輸出內容為 >

Set-Cookie: c1=a; path=/; domain=localhostSet-Cookie: c2=b; path="/", c3=c; domain="localhost"2

獲得所有頭部給定類型的最有效的方法是使用
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());}

輸出內容為 >

Set-Cookie: c1=a; path=/; domain=localhostSet-Cookie: c2=b; path="/", c3=c; domain="localhost"

它還提供了方便的方法來解析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]); }}

輸出內容為 >

c1 = apath=/domain=localhostc2 = bpath=/c3 = cdomain=localhost

1.1.4. HTTP 實體

HTTP 消息可以攜帶與其相關聯的請求或響應的內容實體。實體可以在一些請求和響應中找到,因為它們也是可選的。使用了實體的請求被稱為封閉實體請求。HTTP規範定義了兩種封閉實體的方法: POST
PUT。響應通常期望包含一個內容實體。 這個規則也有特例,就像
HEAD 方法和 204 No Content,
304 Not Modified, 205 Reset Content
響應。

HttpClient根據其內容來源以此區分三種類型的實體:

  • streamed(流式): 
    從流中獲取或者是動態生成內容。尤其是這個類型包含了從HTTP響應中獲取的實體。流式實體是不可重複生成的。

  • self-contained(自包含式): 
    通過內存、使用獨立的連接、其他實體的方式來獲得內容。自包含實體可以重複生成。這種類型的實體將主要被用於封閉HTTP請求。

  • wrapping(包裝式): 
    通過其他實體來獲得內容.

當一個HTTP請求中正在流式輸出內容時,這個區分對於連接管理來說很重要。而對於由應用程序創建,並且只使用 HttpClient 發送的請求實體,流式和自包含的區分是沒有多大意義的。在這種情况下,建議考慮如流式這樣的非可重複的實體,或者是像自包含式那樣的可重複實體。

1.1.4.1. 重複實體

一個可重複的實體,這意味著它的內容可以被多次讀取。
只有自包含式才可能會有這樣的實體 (比如
ByteArrayEntity or
StringEntity)

1.1.4.2. 使用 HTTP 實體

由於一個實體可以同時錶示二進制和字符內容,因此它擁有對字符編碼的支持(對後者支持,即支持字符內容)。

當執行一次使用封閉內容的請求或者是當請求成功後,響應體被當做返回結果發回客戶端的時候創建實體。

要讀取實體中的內容, 可以通過 HttpEntity#getContent() 方法來從輸入流中獲取, 它會返回 java.io.InputStream對象。 或者提供一個輸出流到 HttpEntity#writeTo(OutputStream) 方法,
這會返回提供的流中已經寫入的全部內容。

當實體已經接收到傳入的消息, 使用
HttpEntity#getContentType()方法和
HttpEntity#getContentLength() 方法能够讀取通用元數據,例如 Content-Type
Content-Length 頭不 (如果它們是可用的). 當
Content-Type 頭部包含對文本 mime類型的字符編碼比如 text/plain 和text/html時,
HttpEntity#getContentEncoding() 方法可以用來讀取這些信息. 當這些頭部不可用時, 將會返回長度為 -1 和內容類型為NULL .如果 Content-Type
頭部是可用的, 將會返回一個 Header 對象

當要為一個傳出消息創建實體時,元數據必須由實體創建者來提供。

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);

輸出內容 >

Content-Type: text/plain; charset=utf-817important message17

1.1.5. 確保低級別資源的釋放

為了確保能够系統資源的正確釋放,必須關閉實體或響應自身相關的內容流。

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 { // do something useful } finally { instream.close(); } }} finally { response.close();}

關閉內容流和關閉響應之間的差別在於,前者將試圖通過消耗實體內容來維持底層連接可用,而後者將立即關閉和丟弃連接。

請注意, HttpEntity#writeTo(OutputStream)
方法也同樣確保系統資源在實體被全部寫出的時候必須正確的釋放,如果該方法獲得的實例通過類
java.io.InputStream 調用了
HttpEntity#getContent()方法, 那麼它會被預期在finally子句關閉流。

當流實體工作時, 能够使用
EntityUtils#consume(HttpEntity) 方法確保
實體內容被充分的消耗和關閉底層流.

有可能出現這樣的特殊情况,只需要獲取響應內容的其中一小部分或者是通過消耗剩餘內容來使連接可重用造成性能損失太高,這樣的情况下可以通過關閉響應來終止內容流。

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(); // Do not need the rest }} finally { response.close();}

這樣做了之後,連接將不能被重用,而且其所持有的所有級別資源會被正確釋放.

1.1.6. 消耗實體內容

通常推薦消耗實體內容的方式是使用
HttpEntity#getContent() 或是
HttpEntity#writeTo(OutputStream) 方法。 HttpClient
同樣也配備了 EntityUtils 類, 它公開了一些靜態方法,這些方法能够更容易地從實體中讀取內容或信息,
替代通過 java.io.InputStream 類這樣直接讀取的方式,並且也可以使用這個類中的方法以字符串/字節數組的形式獲取整個內容體。
但是, 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();}

在某些情况下可能需要能够讀取的實體內容超過一次。在這種情况下的實體內容必須以某種方式緩存在內存或磁盤上。解决這個問題最簡單的方式是通過
the BufferedHttpEntity 類來包裝源實體。這將使源實體的內容被讀入到內存緩沖區。其他任何方式的實體包裝都會包含源實體。

CloseableHttpResponse response = <...>HttpEntity entity = response.getEntity();if (entity != null) { entity = new BufferedHttpEntity(entity);}

1.1.7. 生成實體內容

HttpClient提供了一些可以通過 HTTP 連接來高效地流出內容的類。 這些類的實例可以與封閉像 POSTPUT請求的實體相關聯,
使得實體內容裝入流出的HTTP 請求。HttpClient為大多數的通用的數據容器比如字符串,字節數組,輸入流和文件提供了一些類: 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);

請注意, InputStreamEntity 是不可重複的,因為它僅能從底層數據流中讀取一次內容。
通常建議來實現一個自定義 HttpEntity 類, 這個是自包含式的類來替代通用類 InputStreamEntity.
FileEntity 也是一個很不錯的點子.

1.1.7.1. HTML 錶單

許多應用程序需要模擬一個提交 HTML 錶單的過程,例如,登錄web應用或提交數據。 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編碼來編碼參數,生成如下的內容::

param1=value1&param2=value2

1.1.7.2. 內容分塊

開始傳輸前,通常建議讓 HttpClient 選擇基於HTTP消息屬性的最適當的傳輸編碼方式。
不過當設置HttpEntity#setChunked()方法為true時,通知HttpClient該塊編碼是首選。 請注意
HttpClient將此標識只作為一個提示. 當使用的HTTP協議不支持塊編碼,比如使用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.1.8. 響應處理程序

處理響應最簡單方便的方式是使用 ResponseHandler 接口, 它包含了
handleResponse(HttpResponse response) 方法。
這個方法徹底的解决了用戶對於連接管理的困擾。當使用
ResponseHandler接口時, 無論是否請求執行成功或引發异常,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);

 

原創文章,轉載請注明: 轉載自並發編程網 – ifeve.com本文鏈接地址: 《HttpClient官方文檔》1.1 執行請求

FavoriteLoading添加本文到我的收藏
版权声明:本文为[杜老師說]所创,转载请带上原文链接,感谢。 https://gsmany.com/2022/01/202201070551269540.html