1.1 HttpClient的最重要的功能是執(zhí)行HTTP方法。一個(gè)HTTP方法的執(zhí)行涉及到一個(gè)或多個(gè)HTTP請(qǐng)求或HTTP響應(yīng)的交流,HttpClient通常是在內(nèi)部處理的。用戶將提供一個(gè)執(zhí)行請(qǐng)求對(duì)象,HttpClient發(fā)送請(qǐng)求到目標(biāo)服務(wù)器返回一個(gè)相應(yīng)的響應(yīng)對(duì)象,如果執(zhí)行失敗則拋出一個(gè)異常。所以,HttpClient API的主要切入點(diǎn)是HttpClient的接口,它定義了上述約定。 下面是一個(gè)請(qǐng)求執(zhí)行過(guò)程中的最簡(jiǎn)單形式的例子: HttpClient httpclient = new DefaultHttpClient(); HttpGet httpget = new HttpGet("http://localhost/"); HttpResponse response = httpclient.execute(httpget); HttpEntity entity = response.getEntity(); if (entity != null) { } 1.1.1 所有的HTTP請(qǐng)求包含一個(gè)由請(qǐng)求行組成的一個(gè)方法名,一個(gè)請(qǐng)求的URI和一個(gè)HTTP協(xié)議的版本。 HttpClient的支持在HTTP/1.1規(guī)范中定義的所有的HTTP方法:GET, HEAD, POST, PUT, DELETE, TRACE 和 OPTIONS。每有一個(gè)方法都有一個(gè)對(duì)應(yīng)的類:HttpGet,HttpHead,HttpPost,HttpPut,HttpDelete,HttpTrace和HttpOptions。所有的這些類均實(shí)現(xiàn)了HttpUriRequest接口,故可以作為execute的執(zhí)行參數(shù)使用。請(qǐng)求URI是能夠應(yīng)用請(qǐng)求的統(tǒng)一資源標(biāo)識(shí)符。 HTTP請(qǐng)求的URI包含一個(gè)協(xié)議計(jì)劃protocol scheme,主機(jī)名host name,,可選的端口optional port,資源的路徑resource path,可選的查詢optional query和可選的片段optional fragment。 HttpGet httpget = new HttpGet( HttpClient提供了一系列實(shí)用的方法來(lái)簡(jiǎn)化創(chuàng)建和修改請(qǐng)求URI。 URI可以組裝編程: URI uri = URIUtils.createURI("http", "www.google.com", -1, "/search", HttpGet httpget = new HttpGet(uri); System.out.println(httpget.getURI()); 輸出> http://www.google.com/search?q=httpclient&btnG=Google+Search&aq=f&oq= 查詢字符串也可以通過(guò)添加參數(shù)列表來(lái)生成: List<NameValuePair> qparams = new ArrayList<NameValuePair>(); qparams.add(new BasicNameValuePair("q", "httpclient")); qparams.add(new BasicNameValuePair("btnG", "Google Search")); qparams.add(new BasicNameValuePair("aq", "f")); qparams.add(new BasicNameValuePair("oq", null)); URI uri = URIUtils.createURI("http", "www.google.com", -1, "/search", 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響應(yīng)是由服務(wù)器收到和解釋一個(gè)請(qǐng)求消息后返回給客戶端的消息。該消息的第一行包含遵循的協(xié)議版本,他由一個(gè)數(shù)字狀態(tài)代碼及其相關(guān)的文本來(lái)表示。 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.1 200 OK HTTP/1.1 200 OK 1.1.3 一個(gè)HTTP消息可以包含一系列headers參數(shù)描述信息,例如內(nèi)容長(zhǎng)度,內(nèi)容類型等。 HttpClient的提供方法來(lái)檢索,添加,刪除和枚舉headers。 HttpResponse response = new BasicHttpResponse(HttpVersion.HTTP_1_1, 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=localhost Set-Cookie: c2=b; path="/", c3=c; domain="localhost" 2 最有效獲取所有的給定類型的headers方式是使用HeaderIterator接口。 HttpResponse response = new BasicHttpResponse(HttpVersion.HTTP_1_1, response.addHeader("Set-Cookie", response.addHeader("Set-Cookie", HeaderIterator it = response.headerIterator("Set-Cookie"); while (it.hasNext()) { } 輸出> Set-Cookie: c1=a; path=/; domain=localhost Set-Cookie: c2=b; path="/", c3=c; domain="localhost" 它還提供了方便的方法來(lái)解析HTTP消息的單個(gè)header元素 HttpResponse response = new BasicHttpResponse(HttpVersion.HTTP_1_1, response.addHeader("Set-Cookie", response.addHeader("Set-Cookie", HeaderElementIterator it = new BasicHeaderElementIterat while (it.hasNext()) { 輸出> c1 = a path=/ domain=localhost c2 = b path=/ c3 = c domain=localhost 1.1.4 HTTP消息的可以進(jìn)行內(nèi)容實(shí)體和請(qǐng)求或響應(yīng)關(guān)聯(lián)。可以在一些要求和一些回應(yīng)中找到實(shí)體,因?yàn)樗鼈兪强蛇x的。實(shí)體內(nèi)附與請(qǐng)求之中。 HTTP規(guī)范定義了兩個(gè)實(shí)體內(nèi)附方法:POST和PUT。響應(yīng)通常將會(huì)附上一個(gè)內(nèi)容實(shí)體。但是響應(yīng)HEAD方法和 204 No Content, 304 Not Modified, 205 Reset Content responses 除外。 HttpClient的區(qū)分三種不同實(shí)體的地方在于內(nèi)容來(lái)源于: streamed流媒體:內(nèi)容是從收到的流,或在運(yùn)行中產(chǎn)生的。特別是包括被從HTTP響應(yīng)收到的實(shí)體。流媒體的實(shí)體一般不可重復(fù)。 self-contained獨(dú)立的:內(nèi)容是在內(nèi)存或以從一個(gè)連接或其他實(shí)體的獨(dú)立獲得的。獨(dú)立的的實(shí)體,一般可重復(fù)的。這種類型的實(shí)體將主要用于內(nèi)附在HTTP請(qǐng)求中。 wrapping包裝:實(shí)體內(nèi)容是從另一個(gè)實(shí)體獲得。 當(dāng)?shù)玫揭粋€(gè)HTTP響應(yīng)流的內(nèi)容的時(shí)候,這種區(qū)分對(duì)于連接管理是很重要的。對(duì)于請(qǐng)求實(shí)體,通過(guò)應(yīng)用程序來(lái)創(chuàng)建和只通過(guò)使用的HttpClient發(fā)送,流和自載之間差別很小。在這種情況下,建議考慮非重復(fù)的流實(shí)體,以及那些重復(fù)的自載實(shí)體。 1.1.4.1 一個(gè)實(shí)體可以是可重復(fù)的,這意味著它的內(nèi)容可以被讀取一次以上。唯一有可能是的獨(dú)立的實(shí)體(如ByteArrayEntity或StringEntity()) 1.1.4.2 由于一個(gè)實(shí)體能夠表示二進(jìn)制和字符的內(nèi)容,它可以提供編碼的支持(支持文字、IE和字符內(nèi)容)。 這個(gè)實(shí)體在執(zhí)行封閉內(nèi)容的請(qǐng)求的時(shí)候或者在請(qǐng)求成功和響應(yīng)返回成功的時(shí)候被創(chuàng)建。 若要讀取從實(shí)體內(nèi)容,一可以通過(guò)檢索HttpEntity#getContent()方法,它返回一個(gè)java.io.InputStream,或一個(gè)可以提供一個(gè)輸出流的HttpEntity#writeTo(OutputStream中)方法的輸入流,這將返回已被寫(xiě)入給定的流的所有內(nèi)容。 當(dāng)通過(guò)傳入的消息收到實(shí)體,方法HttpEntity#getContentType()和 HttpEntity#getContentLength()方法可用于閱讀通用元數(shù)據(jù)metadata,如Content-Type,Content- Length headers(如果可用)。由于Content-Type header可以包含一個(gè)像text/plain或者text/html的文本mime-types的character encoding,HttpEntity#getContentEncoding()方法用來(lái)讀取此信息。如果headers是不可用,返回的長(zhǎng)度是 -1,content type并為NUL。如果Content – Type header可用,將返回一個(gè)header對(duì)象。 當(dāng)創(chuàng)建了一個(gè)即將卸任的消息實(shí)體,該meta data必須提供由該實(shí)體的創(chuàng)造者。 StringEntity myEntity = new StringEntity("important message", System.out.println(myEntity.getContentType()); System.out.println(myEntity.getContentLength()); System.out.println(EntityUtils.getContentCharSet(myEntity)); System.out.println(EntityUtils.toString(myEntity)); System.out.println(EntityUtils.toByteArray(myEntity).length); stdout > Content-Type: text/plain; charset=UTF-8 17 UTF-8 important message 17 1.1.5 當(dāng)響應(yīng)實(shí)體完成之后,重要的是要確保所有的實(shí)體內(nèi)容已被完全消耗,使該連接可以安全地返回到連接池,重新由連接管理器提供給后續(xù)請(qǐng)求使用。最簡(jiǎn)單的方法是調(diào)用HttpEntity#consumeContent()方法來(lái)消耗流上的所有可用的內(nèi)容。當(dāng)檢測(cè)到內(nèi)容已經(jīng)達(dá)到流末尾的時(shí)候,HttpClient會(huì)自動(dòng)釋放底層連接返回到連接管理器。HttpEntity#consumeContent()方法多次調(diào)用也是安全的。 當(dāng)只有小部分實(shí)體響應(yīng)內(nèi)容需要被檢索和消費(fèi)。其余內(nèi)容,使用可重復(fù)的連接性能損失太大,可以簡(jiǎn)單地調(diào)用HttpUriRequest#abort()方法來(lái)終止請(qǐng)求。 HttpGet httpget = new HttpGet("http://localhost/"); HttpResponse response = httpclient.execute(httpget); HttpEntity entity = response.getEntity(); if (entity != null) { } 該連接將不可重用,但是所有資源會(huì)被釋放。 1.1.6 獲取實(shí)體內(nèi)容推薦的方法是通過(guò)使用HttpEntity#getContent()或 HttpEntity#writeTo(OutputStream中)方法。 HttpClient的還配備了EntityUtils類,它暴露了一些靜態(tài)方法,以更輕松地閱讀一個(gè)實(shí)體的內(nèi)容或資料。使用這個(gè)類的方法和直接使用 java.io.InputStream方法不同的是,他可以檢索字符串中的全部?jī)?nèi)容機(jī)構(gòu)/字節(jié)數(shù)組。強(qiáng)烈建議不要使用EntityUtils,除非響應(yīng)實(shí)體來(lái)自一個(gè)可信賴的HTTP服務(wù)器和已知的有限長(zhǎng)度。 HttpGet httpget = new HttpGet("http://localhost/"); HttpResponse response = httpclient.execute(httpget); HttpEntity entity = response.getEntity(); if (entity != null) { } 在某些情況下,實(shí)體內(nèi)容可能需要能夠讀被多次讀取。在這種情況下實(shí)體的內(nèi)容必須以某種方式被緩沖在內(nèi)存或磁盤(pán)上。最簡(jiǎn)單的方法是通過(guò)BufferedHttpEntity類來(lái)封裝原始實(shí)體。原始實(shí)體內(nèi)容可以從內(nèi)存中的緩沖區(qū)來(lái)讀取。其他方式封裝實(shí)體都包含原始實(shí)體。 HttpGet httpget = new HttpGet("http://localhost/"); HttpResponse response = httpclient.execute(httpget); HttpEntity entity = response.getEntity(); if (entity != null) { } 1.1.7 HttpClient提供了一些類可以從HTTP連接內(nèi)容中獲得效地流。這些類的實(shí)例可以與實(shí)體內(nèi)附如POST和PUT請(qǐng)求,以便為即將離任的 HTTP請(qǐng)求附上實(shí)體內(nèi)容。 HttpClient的為最常見(jiàn)的數(shù)據(jù)容器幾類,如串,字節(jié)數(shù)組輸入流和文件:StringEntity,ByteArrayEntity,InputStreamEntity和FileEntity。 File file = new File("somefile.txt"); FileEntity entity = new FileEntity(file, "text/plain; charset="UTF-8""); HttpPost httppost = new HttpPost("http://localhost/action.do"); httppost.setEntity(entity); 請(qǐng)注意InputStreamEntity是不可重復(fù)的,因?yàn)樗荒軓牡讓訑?shù)據(jù)流中讀取一次。一般來(lái)說(shuō),建議實(shí)現(xiàn)自定義HttpEntity類是自載的,而不是使用通用InputStreamEntity。 FileEntity可以是一個(gè)很好的起點(diǎn)。 1.1.7.1 通常的HTTP實(shí)體需要在執(zhí)行上下文的時(shí)候動(dòng)態(tài)生成的。 HttpClient的提供使用EntityTemplate實(shí)體類和ContentProducer接口支持動(dòng)態(tài)實(shí)體。內(nèi)容制作是通過(guò)寫(xiě)需求的內(nèi)容到一個(gè)輸出流,每次請(qǐng)求的時(shí)候都會(huì)產(chǎn)生。因此,通過(guò)EntityTemplate創(chuàng)建實(shí)體通常是獨(dú)立的,重復(fù)性好。 ContentProducer cp = new ContentProducer() { }; HttpEntity entity = new EntityTemplate(cp); HttpPost httppost = new HttpPost("http://localhost/handler.do"); httppost.setEntity(entity); 1.1.7.2 許多應(yīng)用程序經(jīng)常需要模擬一個(gè)HTML表單提交的過(guò)程,例如,以登錄到Web應(yīng)用程序或提交的輸入數(shù)據(jù)。 HttpClient的實(shí)體類UrlEncodedFormEntity可以幫助實(shí)現(xiàn)這一步。 List<NameValuePair> formparams = new ArrayList<NameValuePair>(); formparams.add(new BasicNameValuePair("param1", "value1")); formparams.add(new BasicNameValuePair("param2", "value2")); UrlEncodedFormEntity entity = new UrlEncodedFormEntity(formparams, "UTF-8"); HttpPost httppost = new HttpPost("http://localhost/handler.do"); httppost.setEntity(entity); 這UrlEncodedFormEntity實(shí)例將使用 URL編碼的編碼參數(shù),并出示下列內(nèi)容: param1=value1¶m2=value2 1.1.7.3 一般來(lái)說(shuō),建議當(dāng)HTTP消息的發(fā)送的時(shí)候讓HttpClient的選擇最合適的傳輸編碼。這是可能的,但是,HttpClient首選通過(guò)設(shè)置 HttpEntity#setChunked()為true設(shè)置編碼。請(qǐng)注意的HttpClient將使用這個(gè)標(biāo)志作為提示。當(dāng)使用HTTP協(xié)議的版本不支持時(shí)候該值將被忽略時(shí),如HTTP/1.0的塊編碼。 StringEntity entity = new StringEntity("important message", entity.setChunked(true); HttpPost httppost = new HttpPost("http://localhost/acrtion.do"); httppost.setEntity(entity); 1.1.8 最簡(jiǎn)單和最方便的處理響應(yīng)方式是通過(guò)使用ResponseHandler接口。這種方法完全免除了用戶去擔(dān)心連接管理。無(wú)論執(zhí)行請(qǐng)求是否成功或?qū)е庐惓?,HttpClient的ResponseHandler會(huì)確保自動(dòng)釋放該連接回連接管理器。 HttpClient httpclient = new DefaultHttpClient(); HttpGet httpget = new HttpGet("http://localhost/"); ResponseHandler<byte[]> handler = new ResponseHandler<byte[]>() { }; byte[] response = httpclient.execute(httpget, handler); 1.2 最初的HTTP被設(shè)計(jì)成一個(gè)無(wú)狀態(tài),響應(yīng),要求面向協(xié)議。然而,現(xiàn)實(shí)世界應(yīng)用程序通常需要能夠堅(jiān)持通過(guò)幾個(gè)邏輯上相關(guān)的請(qǐng)求響應(yīng)交換狀態(tài)信息。為了使應(yīng)用程序能夠保持狀態(tài),HttpClient允許 HTTP請(qǐng)求在一個(gè)特定的上下文中執(zhí)行,被稱為HTTP的上下文。如果一個(gè)邏輯同樣的情況下連續(xù)請(qǐng)求之間重用,多個(gè)邏輯相關(guān)的要求可以參加到會(huì)話中,。 HTTP上下文功能類似于java.util.Map的<String, Object>。它只是一個(gè)任意命名的值的集合??梢栽谡?qǐng)求執(zhí)行或者執(zhí)行完畢之后校驗(yàn)下文的時(shí)候在添加屬性參數(shù)到應(yīng)用程序。 在HTTP請(qǐng)求執(zhí)行的過(guò)程中HttpClient添加屬性到執(zhí)行上下文: 'http.connection':HttpConnection實(shí)例代表實(shí)際連接到目標(biāo)服務(wù)器。 'http.target_host':HttpHost實(shí)例代表連接的目標(biāo)。 'http.proxy_host':HttpHost實(shí)例代表連接代理,如果使用 'http.request':HttpRequest實(shí)例代表實(shí)際的HTTP請(qǐng)求。 'http.response':HttpResponse實(shí)例代表了實(shí)際的HTTP響應(yīng)。 'http.request_sent':java.lang.Boolean的對(duì)象,表示該標(biāo)志指示是否實(shí)際的要求已完全傳輸?shù)竭B接的目標(biāo)。 例如,想確定最后的重定向目標(biāo),一種方法可以在要求執(zhí)行之后交驗(yàn)該http.target_host屬性值: DefaultHttpClient httpclient = new DefaultHttpClient(); HttpContext localContext = new BasicHttpContext(); HttpGet httpget = new HttpGet("http://www.google.com/"); HttpResponse response = httpclient.execute(httpget, localContext); HttpHost target = (HttpHost) localContext.getAttribute( System.out.println("Final target: " + target); HttpEntity entity = response.getEntity(); if (entity != null) { entity.consumeContent(); } 輸出> Final target: http://www. 1.3 HttpClient的可以拋出兩種例外情況:在I/O錯(cuò)誤的時(shí)候java.io.IOException如socket timeout或者socket reset。HttpException 如違反了HTTP協(xié)議的HTTP錯(cuò)誤故障。通常的I/O錯(cuò)誤被視為非致命性和可恢復(fù)的,而HTTP協(xié)議錯(cuò)誤被認(rèn)為是致命的錯(cuò)誤,不能自動(dòng)收回。 1.3.1 HTTP協(xié)議并沒(méi)有適用所有應(yīng)用。 HTTP是一個(gè)簡(jiǎn)單的請(qǐng)求/響應(yīng)協(xié)議,最初旨在支持靜態(tài)或動(dòng)態(tài)生成的內(nèi)容檢索。它從未打算支持事務(wù)操作。例如,HTTP服務(wù)器將考慮其對(duì)履行合同的一部分,如果它在接收和處理請(qǐng)求成功,產(chǎn)生了反應(yīng),發(fā)出了一個(gè)狀態(tài)代碼返回給客戶端。該服務(wù)器將不作任何嘗試回滾事務(wù),如果客戶端無(wú)法接收的全部原因是讀超時(shí),要求取消或系統(tǒng)崩潰的反應(yīng)。如果客戶決定重試相同的請(qǐng)求,服務(wù)器將不可避免地最終執(zhí)行相同的交易超過(guò)一次。在某些情況下,這可能導(dǎo)致應(yīng)用數(shù)據(jù)損壞或不一致的應(yīng)用現(xiàn)狀。 雖然HTTP從來(lái)沒(méi)有被設(shè)計(jì)成支持事務(wù)處理,它仍然可以作為傳輸協(xié)議為應(yīng)用程序用執(zhí)行關(guān)鍵任務(wù)。為了確保HTTP傳輸層安全,系統(tǒng)必須確保冪等的HTTP方法在應(yīng)用層。 1.3.2 HTTP/1.1規(guī)范定義冪等方法, 方法含有冪等屬性 指的是(除了錯(cuò)誤或過(guò)期問(wèn)題),N>0的相同請(qǐng)求和一個(gè)單獨(dú)的請(qǐng)求是一樣的。 換句話說(shuō),應(yīng)用程序應(yīng)該確保它準(zhǔn)備處理的多個(gè)執(zhí)行相同的方法的影響。這可以實(shí)現(xiàn)的,例如,通過(guò)提供一個(gè)獨(dú)特的交易ID和避免同一邏輯操作執(zhí)行的其他方式。 請(qǐng)注意,此問(wèn)題不是特定的HttpClient?;跒g覽器應(yīng)用程序是完全符合相關(guān)的HTTP方法非冪等同樣的問(wèn)題。 HttpClient的假設(shè)非實(shí)體內(nèi)附如GET和HEAD是冪等與實(shí)體內(nèi)附 如POST和PUT方法不是。 1.3.3 默認(rèn)情況下的HttpClient嘗試自動(dòng)恢復(fù)從I / O異常。默認(rèn)的自動(dòng)恢復(fù)機(jī)制是限于一個(gè)已知是安全的少數(shù)例外。 HttpClient的將不作任何嘗試從任何邏輯或HTTP協(xié)議錯(cuò)誤(從HttpException類派生的)的恢復(fù)。 HttpClient會(huì)自動(dòng)重試那些被假定為冪等的方法。 HttpClient會(huì)自動(dòng)重試的方法,傳輸失敗異常的HTTP請(qǐng)求仍然被傳輸?shù)侥繕?biāo)服務(wù)器 HttpClient會(huì)自動(dòng)重試那些已經(jīng)完全傳輸?shù)椒?wù)器的方法,但服務(wù)器沒(méi)有響應(yīng)的HTTP狀態(tài)代碼(服務(wù)器只是丟棄不發(fā)送任何東西連接)。在這種情況下,假設(shè)該請(qǐng)求沒(méi)有被服務(wù)器和應(yīng)用程序狀態(tài)的處理并沒(méi)有改變。如果這種假設(shè)可能不適用于您的應(yīng)用程序的Web服務(wù)器是真正的目標(biāo),強(qiáng)烈建議提供一個(gè)自定義的異常處理程序。 1.3.4 為了使自定義的異?;謴?fù)機(jī)制應(yīng)該提供一個(gè)HttpRequestRetryHandler接口的實(shí)現(xiàn)。 DefaultHttpClient httpclient = new DefaultHttpClient(); HttpRequestRetryHandler myRetryHandler = new HttpRequestRetryHandler() { }; httpclient.setHttpRequestRetryHandl 1.4 在某些情況下執(zhí)行HTTP請(qǐng)求未能完成預(yù)期的時(shí)間范圍內(nèi)由于對(duì)目標(biāo)服務(wù)器或客戶端發(fā)出太多的并發(fā)請(qǐng)求的高負(fù)荷。在這種情況下,可能有必要提前終止和解除封鎖的要求執(zhí)行的線程在I / O操作阻塞。 HTTP請(qǐng)求被處決的HttpClient可以在任何援引HttpUriRequest#abort()方法執(zhí)行階段中止。此方法是線程安全的,可以從任何線程調(diào)用。當(dāng)一個(gè)HTTP請(qǐng)求被中止它的執(zhí)行線程阻塞在一個(gè)I / O操作是保證解鎖通過(guò)拋出一個(gè)InterruptedIOException 1.5 HTTP協(xié)議的攔截器是一個(gè)例程,實(shí)現(xiàn)了HTTP協(xié)議的具體內(nèi)容。通常協(xié)議攔截行動(dòng)后,預(yù)計(jì)一個(gè)特定標(biāo)題或傳入的消息頭相關(guān)團(tuán)體或填充一個(gè)特定的頭或一組相關(guān)的頭傳出的消息。議定書(shū)攔截器還可以操縱的消息封閉的實(shí)體內(nèi)容,透明的內(nèi)容壓縮/解壓是一個(gè)很好的例子。通常這是通過(guò)使用'裝飾'的模式,其中一個(gè)包裝實(shí)體類是用來(lái)裝飾的原始實(shí)體。幾個(gè)協(xié)議攔截器可以組合成一個(gè)邏輯單元。 攔截器可以通過(guò)合作協(xié)議共享信息 - 如處理狀態(tài) - 通過(guò)HTTP的執(zhí)行上下文。攔截器可以使用HTTP協(xié)議中的要求來(lái)存儲(chǔ)一個(gè)或多個(gè)連續(xù)的請(qǐng)求處理狀態(tài)。 通常在這種攔截器都執(zhí)行不應(yīng)該的問(wèn)題,只要他們不依賴于特定國(guó)家的執(zhí)行上下文秩序。如果協(xié)議攔截器有相互依存,因此必須在一個(gè)特定的順序執(zhí)行的,他們應(yīng)該被添加到了他們的預(yù)期的執(zhí)行順序相同的順序協(xié)議處理器。 議定書(shū)攔截器必須實(shí)現(xiàn)為線程安全的。同樣到Servlet,協(xié)議攔截器不應(yīng)使用實(shí)例變量,除非獲得這些變量的同步。 這個(gè)例子說(shuō)明本地上下文可用于保存請(qǐng)求的處理之間的連續(xù)狀態(tài): DefaultHttpClient httpclient = new DefaultHttpClient(); HttpContext localContext = new BasicHttpContext(); AtomicInteger count = new AtomicInteger(1); localContext.setAttribute("count", count); httpclient.addRequestInterceptor(new HttpRequestInterceptor() { }); HttpGet httpget = new HttpGet("http://localhost/"); for (int i = 0; i < 10; i++) { } 1.6 HttpParams接口代表一個(gè)不可改變的值的集合,定義一個(gè)組件在運(yùn)行時(shí)行為。在許多方面是相似的HttpContext HttpParams。兩者的主要區(qū)別是他們?cè)谶\(yùn)行時(shí)使用。代表了兩個(gè)接口是作為一個(gè)組織的鍵映射對(duì)象值對(duì)象的集合,而是為不同的目的: HttpParams是為了包含簡(jiǎn)單的對(duì)象:整數(shù),雙打,字符串,集合和對(duì)象在運(yùn)行時(shí)保持不變。 HttpParams預(yù)計(jì)將用在'寫(xiě)一次 - 準(zhǔn)備許多'模式。 HttpContext的目的是包含很可能發(fā)生變異的HTTP消息處理過(guò)程中的復(fù)雜對(duì)象。 該HttpParams目的是確定了其他組件的行為。一般每個(gè)復(fù)雜的組件都有它自己的HttpParams對(duì)象。對(duì)HttpContext的目的,是代表了一個(gè)HTTP進(jìn)程的執(zhí)行狀態(tài)。通常是相同的執(zhí)行上下文之間共享許多合作對(duì)象。 1.6.1 在HTTP請(qǐng)求的HttpRequest對(duì)象執(zhí)行HttpParams當(dāng)然是聯(lián)系在一起的用于執(zhí)行請(qǐng)求的HttpClient的實(shí)例 HttpParams。這使得在HTTP請(qǐng)求參數(shù)水平接管HttpParams優(yōu)先在HTTP客戶端的水平。建議的做法是通過(guò)設(shè)置在HTTP客戶端級(jí)別的共同所有的HTTP請(qǐng)求參數(shù)和選擇性覆蓋在HTTP請(qǐng)求級(jí)別的具體參數(shù)。 DefaultHttpClient httpclient = new DefaultHttpClient(); httpclient.getParams().setParameter(CoreProtocolPNames.PROTOCOL_VERSION, httpclient.getParams().setParameter(CoreProtocolPNames.HTTP_CONTENT_CHARSET, HttpGet httpget = new HttpGet("http://www.google.com/"); httpget.getParams().setParameter(CoreProtocolPNames.PROTOCOL_VERSION, httpget.getParams().setParameter(CoreProtocolPNames.USE_EXPECT_CONTINUE, httpclient.addRequestInterceptor(new HttpRequestInterceptor() { }); 輸出> HTTP/1.1 UTF-8 false null 1.6.2 HttpParams接口為靈活性的實(shí)現(xiàn)在處理組件的配置。最重要的是,新的參數(shù)可以引進(jìn),而不會(huì)影響與舊版本的二進(jìn)制兼容性。然而,HttpParams也具有一定的缺點(diǎn)相比,常規(guī)的Java bean:HttpParams不能直接投資框架組裝使用。為了緩解這種限制,HttpClient的包括bean class,可以使用,以初始化HttpParams對(duì)象使用標(biāo)準(zhǔn)的Java bean約定的class數(shù)目。 HttpParams params = new BasicHttpParams(); HttpProtocolParamBean paramsBean = new HttpProtocolParamBean(params); paramsBean.setVersion(HttpVersion.HTTP_1_1); paramsBean.setContentCharset("UTF-8"); paramsBean.setUseExpectContinue(true); System.out.println(params.getParameter( System.out.println(params.getParameter( System.out.println(params.getParameter( System.out.println(params.getParameter( 輸出> HTTP/1.1 UTF-8 false null 1.7 這些參數(shù)可以影響到執(zhí)行請(qǐng)求的過(guò)程: 'http.protocol.version':定義使用HTTP協(xié)議的版本,如果沒(méi)有就請(qǐng)求對(duì)象明確。預(yù)計(jì)此參數(shù)類型ProtocolVersion價(jià)值。如果該參數(shù)沒(méi)有設(shè)置HTTP/1.1中會(huì)被使用。 'http.protocol.element-charset':定義用于編碼字符集是HTTP協(xié)議分子利用。此參數(shù)預(yù)計(jì)java.lang.String類型的值。如果此參數(shù)設(shè)置不美的ASCII將被使用。 'http.protocol.content-charset':定義為每默認(rèn)用于內(nèi)容主體編碼字符集。此參數(shù)預(yù)計(jì)java.lang.String類型的值。如果該參數(shù)沒(méi)有設(shè)置的ISO - 8859 - 1將被使用。 'http.useragent':定義了用戶代理頭的內(nèi)容。此參數(shù)預(yù)計(jì)java.lang.String類型的值。如果此參數(shù)未設(shè)置,HttpClient的將自動(dòng)生成一個(gè)值。 'http.protocol.strict-transfer-encoding':定義是否以無(wú)效傳輸編碼頭的反應(yīng),應(yīng)予以拒絕。預(yù)計(jì)此參數(shù)類型java.lang.Boolean的價(jià)值。如果該參數(shù)沒(méi)有設(shè)置無(wú)效的傳輸編碼值將被忽略。 'http.protocol.expect-continue':激活期望:為封閉的方法,實(shí)體100繼續(xù)握手。作者期望的目的:100繼續(xù)握手,是讓客戶端發(fā)送一個(gè)請(qǐng)求主體請(qǐng)求消息,以確定是否愿意到原始服務(wù)器之前接受客戶端發(fā)送請(qǐng)求的請(qǐng)求(根據(jù)請(qǐng)求頭)機(jī)構(gòu)。作者期望使用:100繼續(xù)握手會(huì)導(dǎo)致一個(gè)附有如POST和PUT請(qǐng)求(實(shí)體顯著的性能改進(jìn)),要求在目標(biāo)服務(wù)器的身份驗(yàn)證。預(yù)計(jì):100繼續(xù)握手應(yīng)謹(jǐn)慎使用,因?yàn)樗赡軙?huì)導(dǎo)致與HTTP 代理服務(wù)器的問(wèn)題和不支持HTTP/1.1協(xié)議。預(yù)計(jì)此參數(shù)類型java.lang.Boolean的價(jià)值。如果該參數(shù)沒(méi)有設(shè)置的HttpClient將嘗試使用握手。 'http.protocol.wait-for-continue':定義了以毫秒為單位的時(shí)間最長(zhǎng)的客戶應(yīng)該花費(fèi)100繼續(xù)等待響應(yīng)。預(yù)計(jì)此參數(shù)類型java.lang.Integer價(jià)值。如果該參數(shù)沒(méi)有設(shè)置的HttpClient將等待一段時(shí)間才能恢復(fù)請(qǐng)求的身體傳送確認(rèn)3秒。 |
|
來(lái)自: 真愛(ài)圖書(shū) > 《android》