Commons-httpclient項(xiàng)目就是專門設(shè)計(jì)來簡化HTTP客戶端與服務(wù)器進(jìn)行各種通訊編程。
1. 讀取網(wǎng)頁(HTTP/HTTPS)內(nèi)容 最簡單的HTTP客戶端,用來演示通過GET或者POST方式訪問某個(gè)頁面
package http.demo; import java.io.IOException; import org.apache.commons.httpclient.*; import org.apache.commons.httpclient.methods.*; public class SimpleClient { public static void main(String[] args) throws IOException { HttpClient client = new HttpClient(); //設(shè)置代理服務(wù)器地址和端口 //client.getHostConfiguration().setProxy("proxy_host_addr",proxy_port); //使用GET方法,如果服務(wù)器需要通過HTTPS連接,那只需要將下面URL中的http換成https HttpMethod method = new GetMethod("http://java."); //使用POST方法 //HttpMethod method = new PostMethod("http://java."); client.executeMethod(method); //打印服務(wù)器返回的狀態(tài) System.out.println(method.getStatusLine()); //打印返回的信息 System.out.println(method.getResponseBodyAsString()); //釋放連接 method.releaseConnection(); } } 2. 以GET或者POST方式向網(wǎng)頁提交參數(shù)
package http.demo; import java.io.IOException; import org.apache.commons.httpclient.*; import org.apache.commons.httpclient.methods.*; /** * 提交參數(shù)演示 * 該程序連接到一個(gè)用于查詢手機(jī)號碼所屬地的頁面 * 以便查詢號碼段1330227所在的省份以及城市 */ 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方式提交數(shù)據(jù) client.executeMethod(method); //打印服務(wù)器返回的狀態(tài) System.out.println(method.getStatusLine()); //打印結(jié)果頁面 String response = new String(method.getResponseBodyAsString().getBytes("8859_1")); //打印返回的信息 System.out.println(response); method.releaseConnection(); } /** * 使用GET方式提交數(shù)據(jù) * @return */ private static HttpMethod getGetMethod(){ return new GetMethod("/simcard.php?simcard=1330227"); } /** * 使用POST方式提交數(shù)據(jù) * @return */ private static HttpMethod getPostMethod(){ PostMethod post = new PostMethod("/simcard.php"); NameValuePair simcard = new NameValuePair("simcard","1330227"); post.setRequestBody(new NameValuePair[] { simcard}); return post; } } 3. 處理頁面重定向 詳細(xì)描述: 狀態(tài)碼 對應(yīng)HttpServletResponse的常量 301 SC_MOVED_PERMANENTLY 頁面已經(jīng)永久移到另外一個(gè)新地址 302 SC_MOVED_TEMPORARILY 頁面暫時(shí)移動到另外一個(gè)新的地址 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"); } } 4. 模擬輸入用戶名和口令進(jìn)行登錄 本小節(jié)應(yīng)該說是HTTP客戶端編程中最常碰見的問題,很多網(wǎng)站的內(nèi)容都只是對注冊用戶可見的,這種情況下就必須要求使用正確的用戶名和口令登錄成功后,方可瀏覽到想要的頁面。因?yàn)镠TTP協(xié)議是無狀態(tài)的,也就是連接的有效期只限于當(dāng)前請求,請求內(nèi)容結(jié)束后連接就關(guān)閉了。在這種情況下為了保存用戶的登錄信息必須使用到Cookie機(jī)制。以JSP/Servlet為例,當(dāng)瀏覽器請求一個(gè)JSP或者是Servlet的頁面時(shí),應(yīng)用服務(wù)器會返回一個(gè)參數(shù),名為jsessionid(因不同應(yīng)用服務(wù)器而異),值是一個(gè)較長的唯一字符串的Cookie,這個(gè)字符串值也就是當(dāng)前訪問該站點(diǎn)的會話標(biāo)識。瀏覽器在每訪問該站點(diǎn)的其他頁面時(shí)候都要帶上jsessionid這樣的Cookie信息,應(yīng)用服務(wù)器根據(jù)讀取這個(gè)會話標(biāo)識來獲取對應(yīng)的會話信息。 對于需要用戶登錄的網(wǎng)站,一般在用戶登錄成功后會將用戶資料保存在服務(wù)器的會話中,這樣當(dāng)訪問到其他的頁面時(shí)候,應(yīng)用服務(wù)器根據(jù)瀏覽器送上的Cookie中讀取當(dāng)前請求對應(yīng)的會話標(biāo)識以獲得對應(yīng)的會話信息,然后就可以判斷用戶資料是否存在于會話信息中,如果存在則允許訪問頁面,否則跳轉(zhuǎn)到登錄頁面中要求用戶輸入賬號和口令進(jìn)行登錄。這就是一般使用JSP開發(fā)網(wǎng)站在處理用戶登錄的比較通用的方法。 對于HTTP的客戶端來講,如果要訪問一個(gè)受保護(hù)的頁面時(shí)就必須模擬瀏覽器所做的工作,首先就是請求登錄頁面,然后讀取Cookie值;再次請求登錄頁面并加入登錄頁所需的每個(gè)參數(shù);最后就是請求最終所需的頁面。當(dāng)然在除第一次請求外其他的請求都需要附帶上 Cookie信息以便服務(wù)器能判斷當(dāng)前請求是否已經(jīng)通過驗(yàn)證。
package http.demo; import org.apache.commons.httpclient.*; import org.apache.commons.httpclient.cookie.*; import org.apache.commons.httpclient.methods.*; /** * 用來演示登錄表單的示例 */ 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格式參數(shù) 提交XML格式的參數(shù)很簡單,僅僅是一個(gè)提交時(shí)候的ContentType問題,下面的例子演示從文件文件中讀取XML信息并提交給服務(wù)器的過程,該過程可以用來測試Web服務(wù)。
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格式數(shù)據(jù)的例子 */ 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”); // 設(shè)置請求的內(nèi)容直接從文件中讀取 post.setRequestBody(new FileInputStream(input)); if (input.length() < Integer.MAX_VALUE) post.setRequestContentLength(input.length()); else post.setRequestContentLength(EntityEnclosingMethod.CONTENT_LENGTH_CHUNKED); // 指定請求內(nèi)容的類型 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使用了單獨(dú)的一個(gè)HttpMethod子類來處理文件的上傳,這個(gè)類就是MultipartPostMethod,該類已經(jīng)封裝了文件上傳的細(xì)節(jié),我們要做的僅僅是告訴它我們要上傳文件的全路徑即可,下面的代碼片段演示如何使用這個(gè)類。
MultipartPostMethod filePost = new MultipartPostMethod(targetURL); filePost.addParameter("fileName", targetFilePath); HttpClient client = new HttpClient(); //由于要上傳的文件可能比較大,因此在此設(shè)置最大的連接超時(shí)時(shí)間 client.getHttpConnectionManager().getParams().setConnectionTimeout(5000); int status = client.executeMethod(filePost); 上面代碼中,targetFilePath即為要上傳的文件所在的路徑。 7. 訪問啟用認(rèn)證的頁面 我們經(jīng)常會碰到這樣的頁面,當(dāng)訪問它的時(shí)候會彈出一個(gè)瀏覽器的對話框要求輸入用戶名和密碼后方可,這種用戶認(rèn)證的方式不同于我們在前面介紹的基于表單的用戶身份驗(yàn)證。 這是HTTP的認(rèn)證策略,httpclient支持三種認(rèn)證方式包括: 基本、摘要以及NTLM認(rèn)證。 其中基本認(rèn)證最簡單、通用但也最不安全;摘要認(rèn)證是在HTTP 1.1中加入的認(rèn)證方式, 而NTLM則是微軟公司定義的而不是通用的規(guī)范,最新版本的NTLM是比摘要認(rèn)證還要安全的一種方式。
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.", "realm", new UsernamePasswordCredentials("username", "password") ); GetMethod get = new GetMethod("https://www./products/index.html"); get.setDoAuthentication( true ); int status = client.executeMethod( get ); System.out.println(status+""+ get.getResponseBodyAsString()); get.releaseConnection(); } } 8. 多線程模式下使用httpclient 多線程同時(shí)訪問httpclient,例如同時(shí)從一個(gè)站點(diǎn)上下載多個(gè)文件。對于同一個(gè)HttpConnection 同一個(gè)時(shí)間只能有一個(gè)線程訪問,為了保證多線程工作環(huán)境下不產(chǎn)生沖突,httpclient使用了一個(gè)多線程連接管理器類:MultiThreadedHttpConnectionManager,要使用這個(gè)類很簡單,只需要在構(gòu)造HttpClient實(shí)例的時(shí)候傳入即可,代碼如下:
MultiThreadedHttpConnectionManager connectionManager = new MultiThreadedHttpConnectionManager(); HttpClient client = new HttpClient(connectionManager); 以后盡管訪問client實(shí)例即可。 |
|