一区二区三区日韩精品-日韩经典一区二区三区-五月激情综合丁香婷婷-欧美精品中文字幕专区

分享

httpClient基礎(chǔ)

 真愛(ài)圖書(shū) 2011-02-12

1.1      執(zhí)行請(qǐng)求

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

    InputStream instream = entity.getContent();

    int l;

    byte[] tmp = new byte[2048];

    while ((l = instream.read(tmp)) != -1) {

    }

}

1.1.1        HTTP請(qǐng)求

所有的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(

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

HttpClient提供了一系列實(shí)用的方法來(lái)簡(jiǎn)化創(chuàng)建和修改請(qǐng)求URI。

URI可以組裝編程:

URI uri = URIUtils.createURI("http", "www.google.com", -1, "/search",

    "q=httpclient&btnG=Google+Search&aq=f&oq=", null);

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",

    URLEncodedUtils.format(qparams, "UTF-8"), null);

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)

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        Headers處理

一個(gè)HTTP消息可以包含一系列headers參數(shù)描述信息,例如內(nèi)容長(zhǎng)度,內(nèi)容類型等。 HttpClient的提供方法來(lái)檢索,添加,刪除和枚舉headers。

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=localhost

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

2

最有效獲取所有的給定類型的headers方式是使用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=localhost

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

它還提供了方便的方法來(lái)解析HTTP消息的單個(gè)header元素

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 = a

path=/

domain=localhost

c2 = b

path=/

c3 = c

domain=localhost

1.1.4   HTTP 實(shí)體

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             重復(fù)實(shí)體

一個(gè)實(shí)體可以是可重復(fù)的,這意味著它的內(nèi)容可以被讀取一次以上。唯一有可能是的獨(dú)立的實(shí)體(如ByteArrayEntity或StringEntity())

1.1.4.2             使用HTTP實(shí)體

由于一個(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",

    "UTF-8");

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

    InputStream instream = entity.getContent();

    int byteOne = instream.read();

    int byteTwo = instream.read();

    // Do not need the rest

    httpget.abort();

}

該連接將不可重用,但是所有資源會(huì)被釋放。

1.1.6   獲取實(shí)體內(nèi)容

獲取實(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) {

    long len = entity.getContentLength();

    if (len != -1 && len < 2048) {

        System.out.println(EntityUtils.toString(entity));

    } else {

        // Stream content out

    }

}

在某些情況下,實(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) {

    entity = new BufferedHttpEntity(entity);

}

1.1.7   生產(chǎn)實(shí)體內(nèi)容

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             動(dòng)態(tài)內(nèi)容實(shí)體

通常的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() {

    public void writeTo(OutputStream outstream) throws IOException {

        Writer writer = new OutputStreamWriter(outstream, "UTF-8");

        writer.write("<response>");

        writer.write("  <content>");

        writer.write("    important stuff");

        writer.write("  </content>");

        writer.write("</response>");

        writer.flush();

    }

};

HttpEntity entity = new EntityTemplate(cp);

HttpPost httppost = new HttpPost("http://localhost/handler.do");

httppost.setEntity(entity);

1.1.7.2             HTML forms

許多應(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&param2=value2

1.1.7.3             內(nèi)容組塊

一般來(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",

    "text/plain; charset="UTF-8"");

entity.setChunked(true);

HttpPost httppost = new HttpPost("http://localhost/acrtion.do");

httppost.setEntity(entity);

1.1.8   響應(yīng)處理程序

最簡(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[]>() {

    public byte[] handleResponse(

            HttpResponse response) throws ClientProtocolException, IOException {

        HttpEntity entity = response.getEntity();

        if (entity != null) {

            return EntityUtils.toByteArray(entity);

        } else {

            return null;

        }

    }

};

byte[] response = httpclient.execute(httpget, handler);

1.2      HTTP的執(zhí)行上下文

最初的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(

    ExecutionContext.HTTP_TARGET_HOST);

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傳輸安全

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        異常自動(dòng)恢復(fù)

默認(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        請(qǐng)求重試處理程序

為了使自定義的異?;謴?fù)機(jī)制應(yīng)該提供一個(gè)HttpRequestRetryHandler接口的實(shí)現(xiàn)。

DefaultHttpClient httpclient = new DefaultHttpClient();

HttpRequestRetryHandler myRetryHandler = new HttpRequestRetryHandler() {

    public boolean retryRequest(

            IOException exception,

            int executionCount,

            HttpContext context) {

        if (executionCount >= 5) {

            // Do not retry if over max retry count

            return false;

        }

        if (exception instanceof NoHttpResponseException) {

            // Retry if the server dropped connection on us

            return true;

        }

        if (exception instanceof SSLHandshakeException) {

            // Do not retry on SSL handshake exception

            return false;

        }

        HttpRequest request = (HttpRequest) context.getAttribute(

                ExecutionContext.HTTP_REQUEST);

        boolean idempotent = !(request instanceof HttpEntityEnclosingRequest);

        if (idempotent) {

            // Retry if the request is considered idempotent

            return true;

        }

        return false;

    }

};

httpclient.setHttpRequestRetryHandler(myRetryHandler);

1.4      中止請(qǐng)求

在某些情況下執(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é)議

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

    public void process(

            final HttpRequest request,

            final HttpContext context) throws HttpException, IOException {

        AtomicInteger count = (AtomicInteger) context.getAttribute("count");

        request.addHeader("Count", Integer.toString(count.getAndIncrement()));

    }

});

HttpGet httpget = new HttpGet("http://localhost/");

for (int i = 0; i < 10; i++) {

    HttpResponse response = httpclient.execute(httpget, localContext);

    HttpEntity entity = response.getEntity();

    if (entity != null) {

        entity.consumeContent();

    }

}

1.6      HTTP parameters

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        參數(shù)層次

在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,

    HttpVersion.HTTP_1_0);

httpclient.getParams().setParameter(CoreProtocolPNames.HTTP_CONTENT_CHARSET,

    "UTF-8");

HttpGet httpget = new HttpGet("http://www.google.com/");

httpget.getParams().setParameter(CoreProtocolPNames.PROTOCOL_VERSION,

    HttpVersion.HTTP_1_1);

httpget.getParams().setParameter(CoreProtocolPNames.USE_EXPECT_CONTINUE,

    Boolean.FALSE);

httpclient.addRequestInterceptor(new HttpRequestInterceptor() {

    public void process(

            final HttpRequest request,

            final HttpContext context) throws HttpException, IOException {

        System.out.println(request.getParams().getParameter(

                CoreProtocolPNames.PROTOCOL_VERSION));

        System.out.println(request.getParams().getParameter(

                CoreProtocolPNames.HTTP_CONTENT_CHARSET));

        System.out.println(request.getParams().getParameter(

                CoreProtocolPNames.USE_EXPECT_CONTINUE));

        System.out.println(request.getParams().getParameter(

                CoreProtocolPNames.STRICT_TRANSFER_ENCODING));

    }

});

輸出>

HTTP/1.1

UTF-8

false

null

1.6.2        HTTP parameters beans

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(

    CoreProtocolPNames.PROTOCOL_VERSION));

System.out.println(params.getParameter(

    CoreProtocolPNames.HTTP_CONTENT_CHARSET));

System.out.println(params.getParameter(

    CoreProtocolPNames.USE_EXPECT_CONTINUE));

System.out.println(params.getParameter(

    CoreProtocolPNames.USER_AGENT));

輸出>

HTTP/1.1

UTF-8

false

null

1.7        執(zhí)行HTTP請(qǐng)求參數(shù)

這些參數(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秒。

    本站是提供個(gè)人知識(shí)管理的網(wǎng)絡(luò)存儲(chǔ)空間,所有內(nèi)容均由用戶發(fā)布,不代表本站觀點(diǎn)。請(qǐng)注意甄別內(nèi)容中的聯(lián)系方式、誘導(dǎo)購(gòu)買(mǎi)等信息,謹(jǐn)防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請(qǐng)點(diǎn)擊一鍵舉報(bào)。
    轉(zhuǎn)藏 分享 獻(xiàn)花(0

    0條評(píng)論

    發(fā)表

    請(qǐng)遵守用戶 評(píng)論公約

    類似文章 更多

    欧美人妻盗摄日韩偷拍| 日本办公室三级在线观看| 成人精品欧美一级乱黄| 妻子的新妈妈中文字幕| 欧美成人精品国产成人综合| 91日韩在线视频观看| 丰满人妻熟妇乱又伦精另类视频 | 五月的丁香婷婷综合网| 色婷婷日本视频在线观看| 亚洲精品福利视频你懂的| 六月丁香六月综合缴情| 国产精品免费视频视频| 亚洲香艳网久久五月婷婷| 国产精品内射视频免费| 视频一区日韩经典中文字幕| 亚洲成人精品免费在线观看| 免费观看一级欧美大片| 日韩不卡一区二区在线| 欧美午夜视频免费观看| 中文字幕欧美视频二区| 九九热国产这里只有精品| 国产精品蜜桃久久一区二区| 国产在线日韩精品欧美| 日本精品免费在线观看| 国产爆操白丝美女在线观看| 91人妻人人揉人人澡人| 日韩欧美第一页在线观看| 91欧美视频在线观看免费| 麻豆tv传媒在线观看| 亚洲综合一区二区三区在线| 国产成人精品国产亚洲欧洲| 国产大屁股喷水在线观看视频| 大胆裸体写真一区二区| 五月的丁香婷婷综合网| 熟女乱一区二区三区四区| 午夜视频成人在线免费| 亚洲综合色在线视频香蕉视频| 国产麻豆成人精品区在线观看| 国产人妻精品区一区二区三区| 国产精品久久香蕉国产线| 国产一区欧美一区日本道|