卖逼视频免费看片|狼人就干网中文字慕|成人av影院导航|人妻少妇精品无码专区二区妖婧|亚洲丝袜视频玖玖|一区二区免费中文|日本高清无码一区|国产91无码小说|国产黄片子视频91sese日韩|免费高清无码成人网站入口

HttpClient 簡(jiǎn)介

HttpClient 簡(jiǎn)介HttpClient 是 Apache Jakarta Common 下的子項(xiàng)目,可以用來(lái)提供高效的、最新的、功能豐富的支持 HTTP 協(xié)議的客戶端編程工具包,并且它支持 H

HttpClient 簡(jiǎn)介

HttpClient 是 Apache Jakarta Common 下的子項(xiàng)目,可以用來(lái)提供高效的、最新的、功能豐富的支持 HTTP 協(xié)議的客戶端編程工具包,并且它支持 HTTP 協(xié)議最新的版本和建議。本文首先介紹

HTTPClient ,然后根據(jù)作者實(shí)際工作經(jīng)驗(yàn)給出了一些常見(jiàn)問(wèn)題的解決方法。HTTP 協(xié)議可能是現(xiàn)在 Internet 上使用得最多、最重要的協(xié)議了,越來(lái)越多的 Java 應(yīng)用程序需要直接通過(guò) HTTP 協(xié)議來(lái)訪問(wèn)網(wǎng)絡(luò)資源。雖然在 JDK 的 java.net 包中已經(jīng)提供了訪問(wèn) HTTP 協(xié)議的基本功能,但是對(duì)于大部分應(yīng)用程序來(lái)說(shuō),JDK 庫(kù)本身提供的功能還不夠豐富和靈活。HttpClient 是 Apache Jakarta Common 下的子項(xiàng)目,用來(lái)提供高效的、最新的、功能豐富的支持 HTTP 協(xié)議的客戶端編程工具包,并且它支持 HTTP 協(xié)議最新的版本和建議。HttpClient 已經(jīng)應(yīng)用在很多的項(xiàng)目中,比如 Apache Jakarta 上很著名的另外兩個(gè)開(kāi)源項(xiàng)目 Cactus 和 HTMLUnit 都使用了 HttpClient ?,F(xiàn)在HttpClient 最新版本為 HttpClient 4.0-beta2

2.HttpClient 功能介紹

以下列出的是 HttpClient 提供的主要的功能,要知道更多詳細(xì)的功能可以參見(jiàn) HttpClient 的主頁(yè)。

(1)實(shí)現(xiàn)了所有 HTTP 的方法(GET,POST,PUT,HEAD 等)

(2)支持自動(dòng)轉(zhuǎn)向

(3)支持 HTTPS 協(xié)議

(4)支持代理服務(wù)器等

3.HttpClient 基本功能的使用

(1) GET方法

使用 HttpClient 需要以下 6 個(gè)步驟:

,

1. 創(chuàng)建 HttpClient 的實(shí)例

2. 創(chuàng)建某種連接方法的實(shí)例,在這里是 GetMethod 。在 GetMethod 的構(gòu)造函數(shù)中傳入待連接的地址

3. 調(diào)用第一步中創(chuàng)建好的實(shí)例的 execute 方法來(lái)執(zhí)行第二步中創(chuàng)建好的 method 實(shí)例

4. 讀 response

5. 釋放連接。無(wú)論執(zhí)行方法是否成功,都必須釋放連接

6. 對(duì)得到后的內(nèi)容進(jìn)行處理

根據(jù)以上步驟,我們來(lái)編寫(xiě)用GET 方法來(lái)取得某網(wǎng)頁(yè)內(nèi)容的代碼。 大部分情況下 HttpClient 默認(rèn)的構(gòu)造函數(shù)已經(jīng)足夠使用。 HttpClient httpClient = new HttpClient();

創(chuàng)建GET 方法的實(shí)例。在GET 方法的構(gòu)造函數(shù)中傳入待連接的地址即可。用GetMethod 將會(huì)自動(dòng)處理轉(zhuǎn)發(fā)過(guò)程,如果想要把自動(dòng)處理轉(zhuǎn)發(fā)過(guò)程去掉 的話,可以調(diào)用方法setFollowRedirects(false)。

GetMethod getMethod = new GetMethod(".....");

調(diào)用實(shí)例httpClient 的executeMethod 方法來(lái)執(zhí)行g(shù)etMethod 。由于是執(zhí)行在網(wǎng)絡(luò)上的程序,在運(yùn)行 executeMethod 方法的時(shí)候,需要處理兩個(gè)異常,分別是HttpException 和IOException 。引起第一種異常的原因主要可能是 在構(gòu)造getMethod 的時(shí)候傳入的協(xié)議不對(duì),比如不小心將"http" 寫(xiě)成"htp" ,或者服務(wù)器端返回的內(nèi)容不正常等,并且該異常發(fā)生是不可恢復(fù) 的;第二種異常一般是由于網(wǎng)絡(luò)原因引起的異常,對(duì)于這種異常 (IOException ),HttpClient 會(huì)根據(jù)你指定的恢復(fù)策略自動(dòng)試著重新執(zhí)行executeMethod 方法。HttpClient 的恢復(fù) 策略可以自定義(通過(guò)實(shí)現(xiàn)接口HttpMethodRetryHandler 來(lái)實(shí)現(xiàn))。通過(guò)httpClient 的方法setParameter 設(shè)置你實(shí) 現(xiàn)的恢復(fù)策略,本文中使用的是系統(tǒng)提供的默認(rèn)恢復(fù)策略,該策略在碰到第二類異常的時(shí)候?qū)⒆詣?dòng)重試3次。executeMethod 返回值是一個(gè)整數(shù),表示 了執(zhí)行該方法后服務(wù)

,

器返回的狀態(tài)碼,該狀態(tài)碼能表示出該方法執(zhí)行是否成功、需要認(rèn)證或者頁(yè)面發(fā)生了跳轉(zhuǎn)(默認(rèn)狀態(tài)下GetMethod 的實(shí)例是自動(dòng)處理跳 轉(zhuǎn)的)等。 //設(shè)置成了默認(rèn)的恢復(fù)策略,在發(fā)生異常時(shí)候?qū)⒆詣?dòng)重試3次,在這里你也可以設(shè)置成自定義的恢復(fù)策略

getMethod.getParams().setParameter(HttpMethodParams.RETRY_HANDLER,

new DefaultHttpMethodRetryHandler());

//執(zhí)行g(shù)etMethod

int statusCode = client.executeMethod(getMethod); if (statusCode != HttpStatus.SC_OK) {

System.err.println("Method failed: "

getMethod.getStatusLine());

}

在返回的狀態(tài)碼正確后,即可取得內(nèi)容。取得目標(biāo)地址的內(nèi)容有三種方法:第一種,getResponseBody ,該方法返回的是目標(biāo)的二進(jìn)制的 byte 流;第二種,getResponseBodyAsString ,這個(gè)方法返回的是String 類型,值得注意的是該方法返回的String 的編碼 是根據(jù)系統(tǒng)默認(rèn)的編碼方式,所以返回的String 值可能編碼類型有誤,在本文的" 字符編碼" 部分中將對(duì)此做詳細(xì)介紹;第三 種,

getResponseBodyAsStream ,這個(gè)方法對(duì)于目標(biāo)地址中有大量數(shù)據(jù)需要傳輸是最佳的。在這里我們使用了最簡(jiǎn)單的 getResponseBody 方法。 byte[] responseBody = method.getResponseBody(); 釋放連接。無(wú)論執(zhí)行方法是否成功,都必須釋放連接。

method.releaseConnection();

處理內(nèi)容。在這一步中根據(jù)你的需要處理內(nèi)容,在例子中只是簡(jiǎn)單的將內(nèi)容打印到控制臺(tái)。 System.out.println(new

,

String(responseBody));

下面是程序的完整代碼,這些代碼也可在附件中的test.GetSample 中找到。

package test;

import java.io.IOException;

import org.apache.commons.httpclient.*;

import org.apache.commons.httpclient.methods.GetMethod; import

org.apache.commons.httpclient.params.HttpMethodParams; public class GetSample{

public static void main(String[] args) {

//構(gòu)造HttpClient 的實(shí)例

HttpClient httpClient = new HttpClient();

//創(chuàng)建GET 方法的實(shí)例

GetMethod getMethod = new GetMethod("...");

//使用系統(tǒng)提供的默認(rèn)的恢復(fù)策略

getMethod.getParams().setParameter(HttpMethodParams.RETRY_HANDLER,

new DefaultHttpMethodRetryHandler());

try {

//執(zhí)行g(shù)etMethod

int statusCode = httpClient.executeMethod(getMethod); if (statusCode != HttpStatus.SC_OK) {

System.err.println("Method failed: "

getMethod.getStatusLine());

}

,

//讀取內(nèi)容

byte[] responseBody = getMethod.getResponseBody(); //處理內(nèi)容

System.out.println(new String(responseBody));

} catch (HttpException e) {

//發(fā)生致命的異常,可能是協(xié)議不對(duì)或者返回的內(nèi)容有問(wèn)題

System.out.println("Please check your provided http address!"); e.printStackTrace();

} catch (IOException e) {

//發(fā)生網(wǎng)絡(luò)異常

e.printStackTrace();

} finally {

//釋放連接

getMethod.releaseConnection();

}

}

}

(2)POST 方法

根據(jù)RFC2616,對(duì)POST 的解釋如下:POST 方法用來(lái)向目的服務(wù)器發(fā)出請(qǐng)求,要求它接受被附在請(qǐng)求后的實(shí)體,并把它當(dāng)作請(qǐng)求隊(duì)列(Request-Line )中請(qǐng)求URI 所指定資源的附加新子項(xiàng)。POST 被設(shè)計(jì)成用統(tǒng)一的方法實(shí)現(xiàn)下列功能:

對(duì)現(xiàn)有資源的注釋(Annotation of existing resources) 向電子公告欄、新聞組,郵件列表或類似討論組發(fā)送消息 提交數(shù)據(jù)塊,如將表單的結(jié)果提交給數(shù)據(jù)處理過(guò)程

通過(guò)附加操作來(lái)擴(kuò)展數(shù)據(jù)庫(kù)

調(diào)用HttpClient 中的PostMethod 與GetMethod 類似,除了設(shè)置

,

PostMethod 的實(shí)例與GetMethod 有些不同之 外,剩下的步驟都差不多。在下面的例子中,省去了與GetMethod 相同的步驟,只說(shuō)明與上面不同的地方,并以登錄清華大學(xué)BBS 為例子進(jìn)行說(shuō)明。

構(gòu)造PostMethod 之前的步驟都相同,與GetMethod 一樣,構(gòu)造PostMethod 也需要一個(gè)URI 參數(shù)。在創(chuàng)建了 PostMethod 的實(shí)例之后,需要給method 實(shí)例填充表單的值,在BBS 的登錄表單中需要有兩個(gè)域,第一個(gè)是用戶名(域名叫id ),第二個(gè)是密碼 (域名叫

passwd )。表單中的域用類NameValuePair 來(lái)表示,該類的構(gòu)造函數(shù)第一個(gè)參數(shù)是域名,第二參數(shù)是該域的值;將表單所有的值設(shè)置到

PostMethod 中用方法setRequestBody 。另外由于BBS 登錄成功后會(huì)轉(zhuǎn)向另外一個(gè)頁(yè)面,但是HttpClient 對(duì)于要求接受后繼服 務(wù)的請(qǐng)求,比如POST 和PUT ,不支持自動(dòng)轉(zhuǎn)發(fā),因此需要自己對(duì)頁(yè)面轉(zhuǎn)向做處理。具體的頁(yè)面轉(zhuǎn)向處理請(qǐng)參見(jiàn)下面的" 自動(dòng)轉(zhuǎn)向" 部分。代碼如下: String url = "....";

PostMethod postMethod = new PostMethod(url);

// 填入各個(gè)表單域的值

NameValuePair[] data = { new NameValuePair("id",

"youUserName"),

new NameValuePair("passwd", "yourPwd") };

// 將表單的值放入postMethod 中

postMethod.setRequestBody(data);

// 執(zhí)行postMethod

int statusCode = httpClient.executeMethod(postMethod); // HttpClient對(duì)于要求接受后繼服務(wù)的請(qǐng)求,象POST 和PUT 等不能自動(dòng)處理轉(zhuǎn)發(fā)

// 301或者302

if (statusCode == HttpStatus.SC_MOVED_PERMANENTLY ||

,

statusCode == HttpStatus.SC_MOVED_TEMPORARILY) { // 從頭中取出轉(zhuǎn)向的地址

Header locationHeader =

postMethod.getResponseHeader("location");

String location = null;

if (locationHeader != null) {

location = locationHeader.getValue();

System.out.println("The page was redirected to:" location); } else {

System.err.println("Location field value is null.");

}

return;

}

[編輯本段]4 使用HttpClient 過(guò)程中常見(jiàn)的一些問(wèn)題 下面介紹在使用HttpClient 過(guò)程中常見(jiàn)的一些問(wèn)題。

字符編碼

某目標(biāo)頁(yè)的編碼可能出現(xiàn)在兩個(gè)地方,第一個(gè)地方是服務(wù)器返回的http 頭中,另外一個(gè)地方是得到的html/xml頁(yè)面中。

在http 頭的Content-Type 字段可能會(huì)包含字符編碼信息。例如可能返回的頭會(huì)包含這樣子的信息:Content-Type: text/html;

charset=UTF-8。這個(gè)頭信息表明該頁(yè)的編碼是UTF-8,但是服務(wù)器返回的頭信息未必與內(nèi)容能匹配上。比如對(duì)于一些雙字節(jié)語(yǔ)言國(guó)家,可能服務(wù) 器返回的編碼類型是UTF-8,但真正的內(nèi)容卻不是UTF-8編碼的,因此需要在另外的地方去得到頁(yè)面的編碼信息;但是如果服務(wù)器返回的編碼不是UTF- 8,而是具體的一些編碼,比如gb2312等,那服務(wù)器返回的可能是正確的編碼信息。通過(guò)method 對(duì)象的getResponseCharSet()方 法就可以得到http 頭中的編碼信息。

,

對(duì)于象xml 或者h(yuǎn)tml 這樣的文件,允許作者在頁(yè)面中直接指定編碼類型。比如在html 中會(huì)有

content="text/html; charset=gb2312"/>這樣的標(biāo)簽;或者在xml 中會(huì)有這樣的標(biāo)簽,在這些情況下,可能與http 頭中返回的編碼信息沖突,需要用戶自己判斷到底那種編碼類型應(yīng)該 是真正的編碼。

自動(dòng)轉(zhuǎn)向

根據(jù)RFC2616中對(duì)自動(dòng)轉(zhuǎn)向的定義,主要有兩種:301和302。301表示永久的移走(Moved Permanently),當(dāng)返回的是301,則表示請(qǐng)求的資源已經(jīng)被移到一個(gè)固定的新地方,任何向該地址發(fā)起請(qǐng)求都會(huì)被轉(zhuǎn)到新的地址上。302表示暫時(shí) 的轉(zhuǎn)向,比如在服務(wù)器端的servlet 程序調(diào)用了sendRedirect 方法,則在客戶端就會(huì)得到一個(gè)302的代碼,這時(shí)服務(wù)器返回的頭信息中 location 的值就是sendRedirect 轉(zhuǎn)向的目標(biāo)地址。

HttpClient 支持自動(dòng)轉(zhuǎn)向處理,但是象POST 和PUT 方式這種要求接受后繼服務(wù)的請(qǐng)求方式,暫時(shí)不支持自動(dòng)轉(zhuǎn)向,因此如果碰到POST 方式 提交后返回的是301或者302的話需要自己處理。就像剛才在

POSTMethod 中舉的例子:如果想進(jìn)入登錄BBS 后的頁(yè)面,必須重新發(fā)起登錄的請(qǐng)求, 請(qǐng)求的地址可以在頭字段location 中得到。不過(guò)需要注意的是,有時(shí)候location 返回的可能是相對(duì)路徑,因此需要對(duì)location 返回的值做 一些處理才可以發(fā)起向新地址的請(qǐng)求。

另外除了在頭中包含的信息可能使頁(yè)面發(fā)生重定向外,在頁(yè)面中也有可能會(huì)發(fā)生頁(yè)面的重定向。引起頁(yè)面自動(dòng)轉(zhuǎn)發(fā)的標(biāo)簽是:。如果你想在程序中也處理這種情況的話得自己分析頁(yè)面來(lái)實(shí)現(xiàn)轉(zhuǎn)向。需要注意的是,在上面那個(gè)標(biāo)簽中url 的值也可以是一個(gè)相對(duì) 地址,如果是這樣的話,需要對(duì)它做一些處理后才可以轉(zhuǎn)發(fā)。

,

處理HTTPS 協(xié)議

HttpClient 提供了對(duì)SSL 的支持,在使用SSL 之前必須安裝JSSE 。在Sun 提供的1.4以后的版本中,JSSE 已經(jīng)集成到JDK 中,如 果你使用的是JDK1.4以前的版本則必須安裝JSSE 。JSSE 不同的廠家有不同的實(shí)現(xiàn)。下面介紹怎么使用HttpClient 來(lái)打開(kāi)Https 連接。 這里有兩種方法可以打開(kāi)https 連接,第一種就是得到服務(wù)器頒發(fā)的證書(shū),然后導(dǎo)入到本地的keystore 中;另外一種辦法就是通過(guò)擴(kuò)展 HttpClient 的類來(lái)實(shí)現(xiàn)自動(dòng)接受證書(shū)。

方法1,取得證書(shū),并導(dǎo)入本地的keystore :

安裝JSSE (如果你使用的JDK 版本是1.4或者1.4以上就可以跳過(guò)這一步)。本文以IBM 的JSSE 為例子說(shuō)明。先到IBM 網(wǎng)站上下載JSSE 的安裝包。然后解 壓開(kāi)之后將ibmjsse.jar 包拷貝到

home>libext目錄下。

取得并且導(dǎo)入證書(shū)。證書(shū)可以通過(guò)IE 來(lái)獲得:

1. 用IE 打開(kāi)需要連接的https 網(wǎng)址,會(huì)彈出如下對(duì)話框:

2. 單擊"View Certificate",在彈出的對(duì)話框中選擇"Details" ,然后再單擊"Copy to File",根據(jù)提供的向?qū)纱L問(wèn)網(wǎng)頁(yè)的證書(shū)文件

3. 向?qū)У谝徊?,歡迎界面,直接單擊"Next" ,

4. 向?qū)У诙剑x擇導(dǎo)出的文件格式,默認(rèn),單擊"Next" ,

5. 向?qū)У谌剑斎雽?dǎo)出的文件名,輸入后,單擊"Next" ,

6. 向?qū)У谒牟?,單?Finish" ,完成向?qū)?/p>

7. 最后彈出一個(gè)對(duì)話框,顯示導(dǎo)出成功

用keytool 工具把剛才導(dǎo)出的證書(shū)倒入本地keystore 。Keytool 命令在bin下,打開(kāi)命令行窗口,并到

home>libsecurity目錄下,運(yùn)行下面的命令:

keytool -import -noprompt -keystore cacerts -storepass changeit -alias yourEntry1 -file your.cer

,

其中參數(shù)alias 后跟的值是當(dāng)前證書(shū)在keystore 中的唯一標(biāo)識(shí)符,但是大小寫(xiě)不區(qū)分;參數(shù)file 后跟的是剛才通過(guò)IE 導(dǎo)出的證書(shū)所在的路徑和文件名;如果你想刪除剛才導(dǎo)入到keystore 的證書(shū),可以用命令: keytool -delete -keystore cacerts -storepass changeit -alias yourEntry1

寫(xiě)程序訪問(wèn)https 地址。如果想測(cè)試是否能連上https ,只需要稍改一下GetSample 例子,把請(qǐng)求的目標(biāo)變成一個(gè)https 地址。 GetMethod getMethod = new GetMethod("your url"); 運(yùn)行該程序可能出現(xiàn)的問(wèn)題:

1. 拋出異常java.net.SocketException: Algorithm SSL not

available 。出現(xiàn)這個(gè)異??赡苁且?yàn)闆](méi)有加JSSEProvider ,如果用的是IBM 的JSSE Provider,在程序中加入這樣的一行:

if(Security.getProvider("com.ibm.jsse.IBMJSSEProvider") == null)

Security.addProvider(new IBMJSSEProvider());

或者也可以打開(kāi)libsecurityjava.security,在行 security.provider.1=sun.security.provider.Sun

security.provider.2=com.ibm.crypto.provider.IBMJCE

后面加入security.provider.3=com.ibm.jsse.IBMJSSEProvider

2. 拋出異常java.net.SocketException: SSL implementation not available 。出現(xiàn)這個(gè)異??赡苁悄銢](méi)有把ibmjsse.jar 拷貝到libext目錄下。

3. 拋出異常javax.net.ssl.SSLHandshakeException: unknown certificate 。出現(xiàn)這個(gè)異常表明你的JSSE 應(yīng)該已經(jīng)安裝正確,但是可能因?yàn)槟銢](méi)有把證書(shū)導(dǎo)入到當(dāng)前運(yùn)行JRE 的keystore 中,請(qǐng)按照前 面介紹的步驟來(lái)導(dǎo)入你的證書(shū)。

方法2,擴(kuò)展HttpClient 類實(shí)現(xiàn)自動(dòng)接受證書(shū)

標(biāo)簽: