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

分享

HttpClient入門

 shaobin0604@163.com 2006-12-28




級別: 高級

發(fā)華 金, 軟件工程師,IBM CSDL, IBM
樟洪 陳, 軟件工程師,IBM CSDL, IBM

2005 年 11 月 10 日

HttpClient 是 Apache Jakarta Common 下的子項目,可以用來提供高效的、最新的、功能豐富的支持 HTTP 協(xié)議的客戶端編程工具包,并且它支持 HTTP 協(xié)議最新的版本和建議。本文首先介紹 HTTPClient,然后根據(jù)作者實際工作經(jīng)驗給出了一些常見問題的解決方法。

HttpClient簡介

HTTP 協(xié)議可能是現(xiàn)在 Internet 上使用得最多、最重要的協(xié)議了,越來越多的 Java 應用程序需要直接通過 HTTP 協(xié)議來訪問網(wǎng)絡資源。雖然在 JDK 的 java.net 包中已經(jīng)提供了訪問 HTTP 協(xié)議的基本功能,但是對于大部分應用程序來說,JDK 庫本身提供的功能還不夠豐富和靈活。HttpClient 是 Apache Jakarta Common 下的子項目,用來提供高效的、最新的、功能豐富的支持 HTTP 協(xié)議的客戶端編程工具包,并且它支持 HTTP 協(xié)議最新的版本和建議。HttpClient 已經(jīng)應用在很多的項目中,比如 Apache Jakarta 上很著名的另外兩個開源項目 Cactus 和 HTMLUnit 都使用了 HttpClient,更多使用 HttpClient 的應用可以參見http://wiki./jakarta-httpclient/HttpClientPowered。HttpClient 項目非?;钴S,使用的人還是非常多的。目前 HttpClient 版本是在 2005.10.11 發(fā)布的 3.0 RC4 。





回頁首


HttpClient 功能介紹

以下列出的是 HttpClient 提供的主要的功能,要知道更多詳細的功能可以參見 HttpClient 的主頁。

  • 實現(xiàn)了所有 HTTP 的方法(GET,POST,PUT,HEAD 等)
  • 支持自動轉(zhuǎn)向
  • 支持 HTTPS 協(xié)議
  • 支持代理服務器等

下面將逐一介紹怎樣使用這些功能。首先,我們必須安裝好 HttpClient。





回頁首


HttpClient 基本功能的使用

GET 方法

使用 HttpClient 需要以下 6 個步驟:

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

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

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

4. 讀 response

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

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

根據(jù)以上步驟,我們來編寫用GET方法來取得某網(wǎng)頁內(nèi)容的代碼。

  • 大部分情況下 HttpClient 默認的構造函數(shù)已經(jīng)足夠使用。
    HttpClient httpClient = new HttpClient();
                                

  • 創(chuàng)建GET方法的實例。在GET方法的構造函數(shù)中傳入待連接的地址即可。用GetMethod將會自動處理轉(zhuǎn)發(fā)過程,如果想要把自動處理轉(zhuǎn)發(fā)過程去掉的話,可以調(diào)用方法setFollowRedirects(false)。
    GetMethod getMethod = new GetMethod("http://www.ibm.com/");
                                

  • 調(diào)用實例httpClient的executeMethod方法來執(zhí)行getMethod。由于是執(zhí)行在網(wǎng)絡上的程序,在運行executeMethod方法的時候,需要處理兩個異常,分別是HttpException和IOException。引起第一種異常的原因主要可能是在構造getMethod的時候傳入的協(xié)議不對,比如不小心將"http"寫成"htp",或者服務器端返回的內(nèi)容不正常等,并且該異常發(fā)生是不可恢復的;第二種異常一般是由于網(wǎng)絡原因引起的異常,對于這種異常 (IOException),HttpClient會根據(jù)你指定的恢復策略自動試著重新執(zhí)行executeMethod方法。HttpClient的恢復策略可以自定義(通過實現(xiàn)接口HttpMethodRetryHandler來實現(xiàn))。通過httpClient的方法setParameter設置你實現(xiàn)的恢復策略,本文中使用的是系統(tǒng)提供的默認恢復策略,該策略在碰到第二類異常的時候?qū)⒆詣又卦?次。executeMethod返回值是一個整數(shù),表示了執(zhí)行該方法后服務器返回的狀態(tài)碼,該狀態(tài)碼能表示出該方法執(zhí)行是否成功、需要認證或者頁面發(fā)生了跳轉(zhuǎn)(默認狀態(tài)下GetMethod的實例是自動處理跳轉(zhuǎn)的)等。
    //設置成了默認的恢復策略,在發(fā)生異常時候?qū)⒆詣又卦?次,在這里你也可以設置成自定義的恢復策略
                                getMethod.getParams().setParameter(HttpMethodParams.RETRY_HANDLER,
                                new DefaultHttpMethodRetryHandler());
                                //執(zhí)行getMethod
                                int statusCode = client.executeMethod(getMethod);
                                if (statusCode != HttpStatus.SC_OK) {
                                System.err.println("Method failed: " + getMethod.getStatusLine());
                                }
                                

  • 在返回的狀態(tài)碼正確后,即可取得內(nèi)容。取得目標地址的內(nèi)容有三種方法:第一種,getResponseBody,該方法返回的是目標的二進制的byte流;第二種,getResponseBodyAsString,這個方法返回的是String類型,值得注意的是該方法返回的String的編碼是根據(jù)系統(tǒng)默認的編碼方式,所以返回的String值可能編碼類型有誤,在本文的"字符編碼"部分中將對此做詳細介紹;第三種,getResponseBodyAsStream,這個方法對于目標地址中有大量數(shù)據(jù)需要傳輸是最佳的。在這里我們使用了最簡單的getResponseBody方法。
    byte[] responseBody = method.getResponseBody();
                                

  • 釋放連接。無論執(zhí)行方法是否成功,都必須釋放連接。
    method.releaseConnection();
                                

  • 處理內(nèi)容。在這一步中根據(jù)你的需要處理內(nèi)容,在例子中只是簡單的將內(nè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) {
                        //構造HttpClient的實例
                        HttpClient httpClient = new HttpClient();
                        //創(chuàng)建GET方法的實例
                        GetMethod getMethod = new GetMethod("http://www.ibm.com");
                        //使用系統(tǒng)提供的默認的恢復策略
                        getMethod.getParams().setParameter(HttpMethodParams.RETRY_HANDLER,
                        new DefaultHttpMethodRetryHandler());
                        try {
                        //執(zhí)行getMethod
                        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é)議不對或者返回的內(nèi)容有問題
                        System.out.println("Please check your provided http address!");
                        e.printStackTrace();
                        } catch (IOException e) {
                        //發(fā)生網(wǎng)絡異常
                        e.printStackTrace();
                        } finally {
                        //釋放連接
                        getMethod.releaseConnection();
                        }
                        }
                        }
                        

POST方法

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

  • 對現(xiàn)有資源的注釋(Annotation of existing resources)
  • 向電子公告欄、新聞組,郵件列表或類似討論組發(fā)送消息
  • 提交數(shù)據(jù)塊,如將表單的結果提交給數(shù)據(jù)處理過程
  • 通過附加操作來擴展數(shù)據(jù)庫

調(diào)用HttpClient中的PostMethod與GetMethod類似,除了設置PostMethod的實例與GetMethod有些不同之外,剩下的步驟都差不多。在下面的例子中,省去了與GetMethod相同的步驟,只說明與上面不同的地方,并以登錄清華大學BBS為例子進行說明。

  • 構造PostMethod之前的步驟都相同,與GetMethod一樣,構造PostMethod也需要一個URI參數(shù),在本例中,登錄的地址是http://www./bbslogin2.php。在創(chuàng)建了PostMethod的實例之后,需要給method實例填充表單的值,在BBS的登錄表單中需要有兩個域,第一個是用戶名(域名叫id),第二個是密碼(域名叫passwd)。表單中的域用類NameValuePair來表示,該類的構造函數(shù)第一個參數(shù)是域名,第二參數(shù)是該域的值;將表單所有的值設置到PostMethod中用方法setRequestBody。另外由于BBS登錄成功后會轉(zhuǎn)向另外一個頁面,但是HttpClient對于要求接受后繼服務的請求,比如POST和PUT,不支持自動轉(zhuǎn)發(fā),因此需要自己對頁面轉(zhuǎn)向做處理。具體的頁面轉(zhuǎn)向處理請參見下面的"自動轉(zhuǎn)向"部分。代碼如下:
    String url = "http://www./bbslogin2.php";
                                PostMethod postMethod = new PostMethod(url);
                                // 填入各個表單域的值
                                NameValuePair[] data = { new NameValuePair("id", "youUserName"),
                                new NameValuePair("passwd", "yourPwd") };
                                // 將表單的值放入postMethod中
                                postMethod.setRequestBody(data);
                                // 執(zhí)行postMethod
                                int statusCode = httpClient.executeMethod(postMethod);
                                // HttpClient對于要求接受后繼服務的請求,象POST和PUT等不能自動處理轉(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;
                                }
                                

完整的程序代碼請參見附件中的test.PostSample





回頁首


使用HttpClient過程中常見的一些問題

下面介紹在使用HttpClient過程中常見的一些問題。

字符編碼

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

  • 在http頭的Content-Type字段可能會包含字符編碼信息。例如可能返回的頭會包含這樣子的信息:Content-Type: text/html; charset=UTF-8。這個頭信息表明該頁的編碼是UTF-8,但是服務器返回的頭信息未必與內(nèi)容能匹配上。比如對于一些雙字節(jié)語言國家,可能服務器返回的編碼類型是UTF-8,但真正的內(nèi)容卻不是UTF-8編碼的,因此需要在另外的地方去得到頁面的編碼信息;但是如果服務器返回的編碼不是UTF-8,而是具體的一些編碼,比如gb2312等,那服務器返回的可能是正確的編碼信息。通過method對象的getResponseCharSet()方法就可以得到http頭中的編碼信息。
  • 對于象xml或者html這樣的文件,允許作者在頁面中直接指定編碼類型。比如在html中會有<meta http-equiv="Content-Type" content="text/html; charset=gb2312"/>這樣的標簽;或者在xml中會有<?xml version="1.0" encoding="gb2312"?>這樣的標簽,在這些情況下,可能與http頭中返回的編碼信息沖突,需要用戶自己判斷到底那種編碼類型應該是真正的編碼。

自動轉(zhuǎn)向

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

HttpClient支持自動轉(zhuǎn)向處理,但是象POST和PUT方式這種要求接受后繼服務的請求方式,暫時不支持自動轉(zhuǎn)向,因此如果碰到POST方式提交后返回的是301或者302的話需要自己處理。就像剛才在POSTMethod中舉的例子:如果想進入登錄BBS后的頁面,必須重新發(fā)起登錄的請求,請求的地址可以在頭字段location中得到。不過需要注意的是,有時候location返回的可能是相對路徑,因此需要對location返回的值做一些處理才可以發(fā)起向新地址的請求。

另外除了在頭中包含的信息可能使頁面發(fā)生重定向外,在頁面中也有可能會發(fā)生頁面的重定向。引起頁面自動轉(zhuǎn)發(fā)的標簽是:<meta http-equiv="refresh" content="5; url=http://www.ibm.com/us">。如果你想在程序中也處理這種情況的話得自己分析頁面來實現(xiàn)轉(zhuǎn)向。需要注意的是,在上面那個標簽中url的值也可以是一個相對地址,如果是這樣的話,需要對它做一些處理后才可以轉(zhuǎn)發(fā)。

處理HTTPS協(xié)議

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

方法1,取得證書,并導入本地的keystore:

  • 安裝JSSE (如果你使用的JDK版本是1.4或者1.4以上就可以跳過這一步)。本文以IBM的JSSE為例子說明。先到IBM網(wǎng)站上下載JSSE的安裝包。然后解壓開之后將ibmjsse.jar包拷貝到<java-home>\lib\ext\目錄下。
  • 取得并且導入證書。證書可以通過IE來獲得:

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




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




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




    4. 向?qū)У诙?,選擇導出的文件格式,默認,單擊"Next",




    5. 向?qū)У谌?,輸入導出的文件名,輸入后,單?Next",




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


    7. 最后彈出一個對話框,顯示導出成功




  • 用keytool工具把剛才導出的證書倒入本地keystore。Keytool命令在<java-home>\bin\下,打開命令行窗口,并到<java-home>\lib\security\目錄下,運行下面的命令:

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

    其中參數(shù)alias后跟的值是當前證書在keystore中的唯一標識符,但是大小寫不區(qū)分;參數(shù)file后跟的是剛才通過IE導出的證書所在的路徑和文件名;如果你想刪除剛才導入到keystore的證書,可以用命令:

    keytool -delete -keystore cacerts -storepass changeit -alias yourEntry1
                                

  • 寫程序訪問https地址。如果想測試是否能連上https,只需要稍改一下GetSample例子,把請求的目標變成一個https地址。
    GetMethod getMethod = new GetMethod("https://www.");
                                

    運行該程序可能出現(xiàn)的問題:

    1. 拋出異常java.net.SocketException: Algorithm SSL not available。出現(xiàn)這個異??赡苁且驗闆]有加JSSEProvider,如果用的是IBM的JSSE Provider,在程序中加入這樣的一行:

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

    或者也可以打開<java-home>\lib\security\java.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)這個異??赡苁悄銢]有把ibmjsse.jar拷貝到<java-home>\lib\ext\目錄下。

    3. 拋出異常javax.net.ssl.SSLHandshakeException: unknown certificate。出現(xiàn)這個異常表明你的JSSE應該已經(jīng)安裝正確,但是可能因為你沒有把證書導入到當前運行JRE的keystore中,請按照前面介紹的步驟來導入你的證書。

方法2,擴展HttpClient類實現(xiàn)自動接受證書

因為這種方法自動接收所有證書,因此存在一定的安全問題,所以在使用這種方法前請仔細考慮您的系統(tǒng)的安全需求。具體的步驟如下:

  • 提供一個自定義的socket factory(test.MySecureProtocolSocketFactory)。這個自定義的類必須實現(xiàn)接口org.apache.commons.httpclient.protocol.SecureProtocolSocketFactory,在實現(xiàn)接口的類中調(diào)用自定義的X509TrustManager(test.MyX509TrustManager),這兩個類可以在隨本文帶的附件中得到
  • 創(chuàng)建一個org.apache.commons.httpclient.protocol.Protocol的實例,指定協(xié)議名稱和默認的端口號
    Protocol myhttps = new Protocol("https", new MySecureProtocolSocketFactory (), 443);
                                

  • 注冊剛才創(chuàng)建的https協(xié)議對象
    Protocol.registerProtocol("https ", myhttps);
                                

  • 然后按照普通編程方式打開https的目標地址,代碼請參見test.NoCertificationHttpsGetSample

處理代理服務器

HttpClient中使用代理服務器非常簡單,調(diào)用HttpClient中setProxy方法就可以,方法的第一個參數(shù)是代理服務器地址,第二個參數(shù)是端口號。另外HttpClient也支持SOCKS代理。



httpClient.getHostConfiguration().setProxy(hostName,port);
                        





回頁首


結論

從上面的介紹中,可以知道HttpClient對http協(xié)議支持非常好,使用起來很簡單,版本更新快,功能也很強大,具有足夠的靈活性和擴展性。對于想在Java應用中直接訪問http資源的編程人員來說,HttpClient是一個不可多得的好工具。



參考資料

  • Commons logging包含了各種各樣的日志API的實現(xiàn),讀者可以通過站點http://jakarta./commons/logging/得到詳細的內(nèi)容

  • Commons codec包含了一些一般的解碼/編碼算法。包含了語音編碼、十六進制、Base64和URL編碼等,通過http://jakarta./commons/codec/可以得到詳細的內(nèi)容

  • rfc2616是關于HTTP/1.1的文檔,可以在http://www./rfcs/rfc2616.html上得到詳細的內(nèi)容,另外rfc1945是關于HTTP/1.0的文檔,通過http://www./rfcs/rfc1945.html可以得到詳細內(nèi)容

  • SSL――SSL 是由 Netscape Communications Corporation 于 1994 年開發(fā)的,而 TLS V1.0 是由 Internet Engineering Task Force(IETF)定義的標準,它基于 SSL V3.0,并且在使用的加密算法上與其有些許的不同。例如,SSL 使用 Message Authentication Code(MAC)算法來生成完整性校驗值,而 TLS 應用密鑰的 Hashing for Message Authentication Code(HMAC)算法。

  • IBM JSSE提供了SSL(Secure Sockets Layer)和TLS(Transport Layer Security)的java實現(xiàn),在http://www-03.ibm.com/servers/eserver/zseries/software/java/jsse.html中可以得到詳細的信息

  • Keytool是一個管理密鑰和證書的工具。關于它詳細的使用信息可以在http://www.doc./csg/java/1.3.1docs/tooldocs/solaris/keytool.html上得到

  • HTTPClient的主頁是http://jakarta./commons/httpclient/,你可以在這里得到關于HttpClient更加詳細的信息


作者簡介

 

金發(fā)華是一名工作在 IBM CSDL 的軟件工程師。他喜歡鉆研各種新的技術,在 Java 網(wǎng)絡開發(fā)和 Web 開發(fā)方面頗有經(jīng)驗。


 

陳樟洪是一位 IBM CSDL 的軟件工程師,目前從事企業(yè)電子商務應用的開發(fā)。

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

    0條評論

    發(fā)表

    請遵守用戶 評論公約

    類似文章 更多

    亚洲最大福利在线观看| 国产精品内射婷婷一级二级| 国产精品亚洲综合天堂夜夜| 日本熟女中文字幕一区| 在线观看中文字幕91| 亚洲高清中文字幕一区二区三区| 日韩精品一区二区毛片| 国产精品久久精品国产| 国产精品成人一区二区在线| 精品国产丝袜一区二区| 激情内射日本一区二区三区| 亚洲午夜av久久久精品| 五月婷婷六月丁香在线观看| 在线观看视频日韩精品| 国产一区二区不卡在线播放| 日本久久精品在线观看| 色涩一区二区三区四区| 99热中文字幕在线精品| 国内午夜精品视频在线观看| 亚洲最新中文字幕一区| 亚洲欧洲在线一区二区三区| 亚洲男人的天堂久久a| 国产精品视频一级香蕉| 爱在午夜降临前在线观看| 亚洲淫片一区二区三区| 少妇成人精品一区二区| 人妻熟女中文字幕在线| 办公室丝袜高跟秘书国产| 国产黑人一区二区三区| 少妇熟女精品一区二区三区| 亚洲男人天堂成人在线视频| 日韩人妻一区二区欧美| 黄色美女日本的美女日人| 久久国产精品亚州精品毛片 | 不卡视频免费一区二区三区| 午夜国产成人福利视频| 观看日韩精品在线视频| 99少妇偷拍视频在线| 出差被公高潮久久中文字幕| 国产欧美亚洲精品自拍| 久久精品国产在热亚洲|