<rt id="bn8ez"></rt>
<label id="bn8ez"></label>

  • <span id="bn8ez"></span>

    <label id="bn8ez"><meter id="bn8ez"></meter></label>

    即使世界明天毀滅,我也要在今天種下我的葡萄樹。
    posts - 112, comments - 14, trackbacks - 0, articles - 11
    一般的情況下我們都是使用IE或者Navigator瀏覽器來訪問一個WEB服務器,用來瀏覽頁面查看信息或者提交一些數據等等。所訪問的這些頁面有的僅僅是一些普通的頁面,有的需要用戶登錄后方可使用,或者需要認證以及是一些通過加密方式傳輸,例如HTTPS。目前我們使用的瀏覽器處理這些情況都不會構成問題。不過你可能在某些時候需要通過程序來訪問這樣的一些頁面,比如從別人的網頁中“偷”一些數據;利用某些站點提供的頁面來完成某種功能,例如說我們想知道某個手機號碼的歸屬地而我們自己又沒有這樣的數據,因此只好借助其他公司已有的網站來完成這個功能,這個時候我們需要向網頁提交手機號碼并從返回的頁面中解析出我們想要的數據來。如果對方僅僅是一個很簡單的頁面,那我們的程序會很簡單,本文也就沒有必要大張旗鼓的在這里浪費口舌。但是考慮到一些服務授權的問題,很多公司提供的頁面往往并不是可以通過一個簡單的URL就可以訪問的,而必須經過注冊然后登錄后方可使用提供服務的頁面,這個時候就涉及到?COOKIE問題的處理。我們知道目前流行的動態網頁技術例如ASP、JSP無不是通過COOKIE來處理會話信息的。為了使我們的程序能使用別人所提供的服務頁面,就要求程序首先登錄后再訪問服務頁面,這過程就需要自行處理cookie,想想當你用java.net.HttpURLConnection?來完成這些功能時是多么恐怖的事情?。r且這僅僅是我們所說的頑固的WEB服務器中的一個很常見的“頑固”!再有如通過HTTP來上傳文件呢?不需要頭疼,這些問題有了“它”就很容易解決了!??

    ?

    ?

    我們不可能列舉所有可能的頑固,我們會針對幾種最常見的問題進行處理。當然了,正如前面說到的,如果我們自己使用?java.net.HttpURLConnection來搞定這些問題是很恐怖的事情,因此在開始之前我們先要介紹一下一個開放源碼的項目,這個項目就是?Apache開源組織中的httpclient,它隸屬于Jakarta的commons項目,目前的版本是2.0RC2。commons下本來已經有一個net的子項目,但是又把httpclient單獨提出來,可見http服務器的訪問絕非易事。

    Commons-httpclient項目就是專門設計來簡化HTTP客戶端與服務器進行各種通訊編程。通過它可以讓原來很頭疼的事情現在輕松的解決,例如你不再管是HTTP或者HTTPS的通訊方式,告訴它你想使用HTTPS方式,剩下的事情交給httpclient替你完成。本文會針對我們在編寫HTTP客戶端程序時經常碰到的幾個問題進行分別介紹如何使用httpclient來解決它們,為了讓讀者更快的熟悉這個項目我們最開始先給出一個簡單的例子來讀取一個網頁的內容,然后循序漸進解決掉前進中的所有問題。

    1.?讀取網頁(HTTP/HTTPS)內容

    下面是我們給出的一個簡單的例子用來訪問某個頁面

    /*

    ?*?Created?on?2003-12-14?by?Liudong

    ?*/

    package?http.demo;

    ?

    import?java.io.IOException;

    ?

    import?org.apache.commons.httpclient.*;

    import?org.apache.commons.httpclient.methods.*;

    /**

    ?*?最簡單的HTTP客戶端,用來演示通過GET或者POST方式訪問某個頁面

    ?*?@author?Liudong

    ?*/

    public?class?SimpleClient?{

    ?

    ????public?static?void?main(String[]?args)?throws?IOException

    ????{

    ????????HttpClient?client?=?new?HttpClient();????

    ????????//設置代理服務器地址和端口?????

    ????????//client.getHostConfiguration().setProxy("proxy_host_addr",proxy_port);

    ????????//使用GET方法,如果服務器需要通過HTTPS連接,那只需要將下面URL中的http換成https

    ????????HttpMethod?method?=?new?GetMethod("http://java.sun.com");?

    ????????//使用POST方法

    ????????//HttpMethod?method?=?new?PostMethod("http://java.sun.com");?

    ????????client.executeMethod(method);

    ????????//打印服務器返回的狀態

    ????????System.out.println(method.getStatusLine());

    ????????//打印返回的信息

    ????????System.out.println(method.getResponseBodyAsString());

    ????????//釋放連接

    ????????method.releaseConnection();

    ????}
    }

    ?

    在這個例子中首先創建一個HTTP客戶端(HttpClient)的實例,然后選擇提交的方法是GET或者POST,最后在HttpClient實例上執行提交的方法,最后從所選擇的提交方法中讀取服務器反饋回來的結果。這就是使用HttpClient的基本流程。其實用一行代碼也就可以搞定整個請求的過程,非常的簡單!


    2.?以GET或者POST方式向網頁提交參數

    其實前面一個最簡單的示例中我們已經介紹了如何使用GET或者POST方式來請求一個頁面,本小節與之不同的是多了提交時設定頁面所需的參數,我們知道如果是GET的請求方式,那么所有參數都直接放到頁面的URL后面用問號與頁面地址隔開,每個參數用&隔開,例如:http://java.sun.com/?name=liudong&mobile=123456,但是當使用POST方法時就會稍微有一點點麻煩。本小節的例子演示向如何查詢手機號碼所在的城市,代碼如下:

    ?

    /*

    ?*?Created?on?2003-12-7?by?Liudong

    ?*/

    package?http.demo;

    ?

    import?java.io.IOException;

    ?

    import?org.apache.commons.httpclient.*;

    import?org.apache.commons.httpclient.methods.*;

    /**

    ?*?提交參數演示

    ?*?該程序連接到一個用于查詢手機號碼所屬地的頁面

    ?*?以便查詢號碼段1330227所在的省份以及城市

    ?*?@author?Liudong

    ?*/

    public?class?SimpleHttpClient?{

    ?

    ????public?static?void?main(String[]?args)?throws?IOException

    ????{

    ????????HttpClient?client?=?new?HttpClient();

    ????????client.getHostConfiguration().setHost("www.imobile.com.cn",?80,?"http");

    ?

    ????????HttpMethod?method?=?getPostMethod();//使用POST方式提交數據

    ????????client.executeMethod(method);

    ???????//打印服務器返回的狀態

    ????????System.out.println(method.getStatusLine());

    ????????//打印結果頁面

    ????????String?response?=

    ???????????new?String(method.getResponseBodyAsString().getBytes("8859_1"));

    ???????//打印返回的信息

    ????????System.out.println(response);

    ????????method.releaseConnection();

    ????}

    ????/**

    ?????*?使用GET方式提交數據

    ?????*?@return

    ?????*/

    ????private?static?HttpMethod?getGetMethod(){

    ????????return?new?GetMethod("/simcard.php?simcard=1330227");

    ????}

    ????/**

    ?????*?使用POST方式提交數據

    ?????*?@return

    ?????*/

    ????private?static?HttpMethod?getPostMethod(){

    ????????PostMethod?post?=?new?PostMethod("/simcard.php");

    ????????NameValuePair?simcard?=?new?NameValuePair("simcard","1330227");

    ????????post.setRequestBody(new?NameValuePair[]?{?simcard});

    ????????return?post;

    ????}

    }

    在上面的例子中頁面http://www.imobile.com.cn/simcard.php需要一個參數是simcard,這個參數值為手機號碼段,即手機號碼的前七位,服務器會返回提交的手機號碼對應的省份、城市以及其他詳細信息。GET的提交方法只需要在URL后加入參數信息,而POST則需要通過NameValuePair類來設置參數名稱和它所對應的值

    3.?處理頁面重定向

    在JSP/Servlet?編程中response.sendRedirect方法就是使用HTTP協議中的重定向機制。它與JSP中的<jsp:forward?…>的區別在于后者是在服務器中實現頁面的跳轉,也就是說應用容器加載了所要跳轉的頁面的內容并返回給客戶端;而前者是返回一個狀態碼,這些狀態碼的可能值見下表,然后客戶端讀取需要跳轉到的頁面的URL并重新加載新的頁面。就是這樣一個過程,所以我們編程的時候就要通過?HttpMethod.getStatusCode()方法判斷返回值是否為下表中的某個值來判斷是否需要跳轉。如果已經確認需要進行頁面跳轉了,那么可以通過讀取HTTP頭中的location屬性來獲取新的地址。

    狀態碼

    對應HttpServletResponse的常量

    詳細描述

    301

    SC_MOVED_PERMANENTLY

    頁面已經永久移到另外一個新地址

    302

    SC_MOVED_TEMPORARILY

    頁面暫時移動到另外一個新的地址

    303

    SC_SEE_OTHER

    客戶端請求的地址必須通過另外的URL來訪問

    307

    SC_TEMPORARY_REDIRECT

    SC_MOVED_TEMPORARILY

    下面的代碼片段演示如何處理頁面的重定向

    client.executeMethod(post);

    ????????System.out.println(post.getStatusLine().toString());?

    ????????post.releaseConnection();

    ????????

    ????????//檢查是否重定向

    ????????int?statuscode?=?post.getStatusCode();

    ????????if?((statuscode?==?HttpStatus.SC_MOVED_TEMPORARILY)?||

    ????????????(statuscode?==?HttpStatus.SC_MOVED_PERMANENTLY)?||

    ????????????(statuscode?==?HttpStatus.SC_SEE_OTHER)?||

    (statuscode?==?HttpStatus.SC_TEMPORARY_REDIRECT))?{

    //讀取新的URL地址

    ????????????Header?header?=?post.getResponseHeader("location");

    ????????????if?(header?!=?null)?{

    ????????????????String?newuri?=?header.getValue();

    ????????????????if?((newuri?==?null)?||?(newuri.equals("")))

    ????????????????????newuri?=?"/";?

    ????????????????GetMethod?redirect?=?new?GetMethod(newuri);

    ????????????????client.executeMethod(redirect);

    ????????????????System.out.println("Redirect:"+?redirect.getStatusLine().toString());?

    ????????????????redirect.releaseConnection();

    ????????????}?else?

    ????????????????System.out.println("Invalid?redirect");

    ????????}

    我們可以自行編寫兩個JSP頁面,其中一個頁面用response.sendRedirect方法重定向到另外一個頁面用來測試上面的例子。



    4.?模擬輸入用戶名和口令進行登錄

    本小節應該說是HTTP客戶端編程中最常碰見的問題,很多網站的內容都只是對注冊用戶可見的,這種情況下就必須要求使用正確的用戶名和口令登錄成功后,方可瀏覽到想要的頁面。因為HTTP協議是無狀態的,也就是連接的有效期只限于當前請求,請求內容結束后連接就關閉了。在這種情況下為了保存用戶的登錄信息必須使用到Cookie機制。以JSP/Servlet為例,當瀏覽器請求一個JSP或者是Servlet的頁面時,應用服務器會返回一個參數,名為jsessionid(因不同應用服務器而異),值是一個較長的唯一字符串的Cookie,這個字符串值也就是當前訪問該站點的會話標識。瀏覽器在每訪問該站點的其他頁面時候都要帶上jsessionid這樣的Cookie信息,應用服務器根據讀取這個會話標識來獲取對應的會話信息。

    對于需要用戶登錄的網站,一般在用戶登錄成功后會將用戶資料保存在服務器的會話中,這樣當訪問到其他的頁面時候,應用服務器根據瀏覽器送上的?Cookie中讀取當前請求對應的會話標識以獲得對應的會話信息,然后就可以判斷用戶資料是否存在于會話信息中,如果存在則允許訪問頁面,否則跳轉到登錄頁面中要求用戶輸入帳號和口令進行登錄。這就是一般使用JSP開發網站在處理用戶登錄的比較通用的方法。

    這樣一來,對于HTTP的客戶端來講,如果要訪問一個受保護的頁面時就必須模擬瀏覽器所做的工作,首先就是請求登錄頁面,然后讀取Cookie值;再次請求登錄頁面并加入登錄頁所需的每個參數;最后就是請求最終所需的頁面。當然在除第一次請求外其他的請求都需要附帶上Cookie信息以便服務器能判斷當前請求是否已經通過驗證。說了這么多,可是如果你使用httpclient的話,你甚至連一行代碼都無需增加,你只需要先傳遞登錄信息執行登錄過程,然后直接訪問想要的頁面,跟訪問一個普通的頁面沒有任何區別,因為類HttpClient已經幫你做了所有該做的事情了,太棒了!下面的例子實現了這樣一個訪問的過程。

    /*

    ?*?Created?on?2003-12-7?by?Liudong

    ?*/

    package?http.demo;

    ?

    import?org.apache.commons.httpclient.*;

    import?org.apache.commons.httpclient.cookie.*;

    import?org.apache.commons.httpclient.methods.*;

    ?

    /**

    ?*?用來演示登錄表單的示例

    ?*?@author?Liudong

    ?*/

    public?class?FormLoginDemo?{

    ?

    ????static?final?String?LOGON_SITE?=?"localhost";

    ????static?final?int????LOGON_PORT?=?8080;

    ????

    ????public?static?void?main(String[]?args)?throws?Exception{

    ????????HttpClient?client?=?new?HttpClient();

    ????????client.getHostConfiguration().setHost(LOGON_SITE,?LOGON_PORT);

    ???????

    ???????//模擬登錄頁面login.jsp->main.jsp

    ????????PostMethod?post?=?new?PostMethod("/main.jsp");

    ????????NameValuePair?name?=?new?NameValuePair("name",?"ld");?????

    ????????NameValuePair?pass?=?new?NameValuePair("password",?"ld");?????

    ????????post.setRequestBody(new?NameValuePair[]{name,pass});

    ???????int?status?=?client.executeMethod(post);

    ????????System.out.println(post.getResponseBodyAsString());

    ????????post.releaseConnection();??

    ???????

    ???????//查看cookie信息

    ????????CookieSpec?cookiespec?=?CookiePolicy.getDefaultSpec();

    ????????Cookie[]?cookies?=?cookiespec.match(LOGON_SITE,?LOGON_PORT,?"/",?false,?client.getState().getCookies());

    ???????if?(cookies.length?==?0)?{

    ???????????System.out.println("None");????

    ???????}?else?{

    ???????????for?(int?i?=?0;?i?<?cookies.length;?i++)?{

    ???????????????System.out.println(cookies[i].toString());????

    ???????????}

    ???????}

    ???????//訪問所需的頁面main2.jsp

    ????????GetMethod?get?=?new?GetMethod("/main2.jsp");

    ????????client.executeMethod(get);

    ????????System.out.println(get.getResponseBodyAsString());

    ????????get.releaseConnection();

    ????}

    }

    5.?提交XML格式參數

    提交XML格式的參數很簡單,僅僅是一個提交時候的ContentType問題,下面的例子演示從文件文件中讀取XML信息并提交給服務器的過程,該過程可以用來測試Web服務。

    import?java.io.File;

    import?java.io.FileInputStream;

    ?

    import?org.apache.commons.httpclient.HttpClient;

    import?org.apache.commons.httpclient.methods.EntityEnclosingMethod;

    import?org.apache.commons.httpclient.methods.PostMethod;

    ?

    /**

    ?*?用來演示提交XML格式數據的例子

    ?*/

    public?class?PostXMLClient?{

    ?

    ????public?static?void?main(String[]?args)?throws?Exception?{

    ????????File?input?=?new?File(“test.xml”);

    ????????PostMethod?post?=?new?PostMethod(“http://localhost:8080/httpclient/xml.jsp”);

    ????????//?設置請求的內容直接從文件中讀取

    ????????post.setRequestBody(new?FileInputStream(input));

    ????????

    ????????if?(input.length()?<?Integer.MAX_VALUE)?

    ????????????post.setRequestContentLength(input.length());

    ????????else????????????post.setRequestContentLength(EntityEnclosingMethod.CONTENT_LENGTH_CHUNKED);

    ????????

    ????????//?指定請求內容的類型

    ????????post.setRequestHeader("Content-type",?"text/xml;?charset=GBK");

    ????????

    ????????HttpClient?httpclient?=?new?HttpClient();?

    ????????int?result?=?httpclient.executeMethod(post);?

    ????????System.out.println("Response?status?code:?"?+?result);

    ????????System.out.println("Response?body:?");

    ????????System.out.println(post.getResponseBodyAsString());

    ????????post.releaseConnection();

    ????}

    }

    6.?通過HTTP上傳文件

    httpclient使用了單獨的一個HttpMethod子類來處理文件的上傳,這個類就是MultipartPostMethod,該類已經封裝了文件上傳的細節,我們要做的僅僅是告訴它我們要上傳文件的全路徑即可,下面的代碼片段演示如何使用這個類。

    MultipartPostMethod?filePost?=?new?MultipartPostMethod(targetURL);

    filePost.addParameter("fileName",?targetFilePath);

    HttpClient?client?=?new?HttpClient();

    //由于要上傳的文件可能比較大,因此在此設置最大的連接超時時間

    client.getHttpConnectionManager().getParams().setConnectionTimeout(5000);

    int?status?=?client.executeMethod(filePost);

    ?

    上面代碼中,targetFilePath即為要上傳的文件所在的路徑。

    7.?訪問啟用認證的頁面

    我們經常會碰到這樣的頁面,當訪問它的時候會彈出一個瀏覽器的對話框要求輸入用戶名和密碼后方可,這種用戶認證的方式不同于我們在前面介紹的基于表單的用戶身份驗證。這是HTTP的認證策略,httpclient支持三種認證方式包括:基本、摘要以及NTLM認證。其中基本認證最簡單、通用但也最不安全;摘要認證是在HTTP?1.1中加入的認證方式,而NTLM則是微軟公司定義的而不是通用的規范,最新版本的NTLM是比摘要認證還要安全的一種方式。

    下面例子是從httpclient的CVS服務器中下載的,它簡單演示如何訪問一個認證保護的頁面:

    import?org.apache.commons.httpclient.HttpClient;

    import?org.apache.commons.httpclient.UsernamePasswordCredentials;

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

    ?

    public?class?BasicAuthenticationExample?{

    ????public?BasicAuthenticationExample()?{

    ????}

    ????public?static?void?main(String[]?args)?throws?Exception?{

    ????????HttpClient?client?=?new?HttpClient();

    ????????client.getState().setCredentials(

    ????????????"www.verisign.com",

    ????????????"realm",

    ????????????new?UsernamePasswordCredentials("username",?"password")

    ????????);

    ????????GetMethod?get?=?new?GetMethod("https://www.verisign.com/products/index.html");

    ????????get.setDoAuthentication(?true?);

    ????????int?status?=?client.executeMethod(?get?);

    ????????System.out.println(status+"\n"+?get.getResponseBodyAsString());

    ????????get.releaseConnection();

    ????}

    }

    8.?多線程模式下使用httpclient

    多線程同時訪問httpclient,例如同時從一個站點上下載多個文件。對于同一個HttpConnection同一個時間只能有一個線程訪問,為了保證多線程工作環境下不產生沖突,httpclient使用了一個多線程連接管理器的類:?MultiThreadedHttpConnectionManager,要使用這個類很簡單,只需要在構造HttpClient實例的時候傳入即可,代碼如下:

    MultiThreadedHttpConnectionManager?connectionManager?=?

    ???new?MultiThreadedHttpConnectionManager();

    HttpClient?client?=?new?HttpClient(connectionManager);

    以后盡管訪問client實例即可。

    參考資料:

    httpclient首頁:????http://jakarta.apache.org/commons/httpclient/
    關于NTLM是如何工作:??http://davenport.sourceforge.net/ntlm.html?


    只有注冊用戶登錄后才能發表評論。


    網站導航:
     
    主站蜘蛛池模板: av无码国产在线看免费网站| 深夜久久AAAAA级毛片免费看| 在线观看免费无码视频| 亚洲高清免费视频| 爱情岛论坛亚洲品质自拍视频网站 | a级毛片在线免费看| 亚洲精品无码鲁网中文电影| 国产福利电影一区二区三区,免费久久久久久久精 | 美女视频黄频a免费观看| 日本视频免费在线| 国产偷国产偷亚洲高清在线| 免费a级毛片无码a∨性按摩| 日本激情猛烈在线看免费观看| 亚洲国产专区一区| 日韩电影免费在线观看网站| 亚洲Av无码专区国产乱码DVD | 国产午夜亚洲精品理论片不卡| sss日本免费完整版在线观看| 亚洲综合网站色欲色欲| 久久永久免费人妻精品| 亚洲国产精品成人久久久| 大地资源在线观看免费高清| 亚洲国产成人精品无码区花野真一| 国产片免费福利片永久| 久久久精品视频免费观看| 亚洲免费视频网站| 免费被黄网站在观看| 一级特黄aaa大片免费看| 亚洲制服中文字幕第一区| 一二三四在线观看免费高清中文在线观看| 亚洲爆乳无码专区www| 超清首页国产亚洲丝袜| 51在线视频免费观看视频| 亚洲精品无码mⅴ在线观看| 亚洲男人天堂2020| 免费人成网站在线观看10分钟| 综合一区自拍亚洲综合图区| 亚洲AV无码一区二区三区系列| 最近中文字幕免费mv视频8| 中文字幕免费观看全部电影| 亚洲AV一二三区成人影片|