一般的情況下我們都是使用IE或者Navigator瀏覽器來訪問一個WEB服務(wù)器,用來瀏覽頁面查看信息或者提交一些數(shù)據(jù)等等。所訪問的這些頁面
有的僅僅是一些普通的頁面,有的需要用戶登錄后方可使用,或者需要認(rèn)證以及是一些通過加密方式傳輸,例如HTTPS。目前我們使用的瀏覽器處理這些情況都
不會構(gòu)成問題。不過你可能在某些時候需要通過程序來訪問這樣的一些頁面,比如從別人的網(wǎng)頁中“偷”一些數(shù)據(jù);利用某些站點(diǎn)提供的頁面來完成某種功能,例如
說我們想知道某個手機(jī)號碼的歸屬地而我們自己又沒有這樣的數(shù)據(jù),因此只好借助其他公司已有的網(wǎng)站來完成這個功能,這個時候我們需要向網(wǎng)頁提交手機(jī)號碼并從
返回的頁面中解析出我們想要的數(shù)據(jù)來。如果對方僅僅是一個很簡單的頁面,那我們的程序會很簡單,本文也就沒有必要大張旗鼓的在這里浪費(fèi)口舌。但是考慮到一
些服務(wù)授權(quán)的問題,很多公司提供的頁面往往并不是可以通過一個簡單的URL就可以訪問的,而必須經(jīng)過注冊然后登錄后方可使用提供服務(wù)的頁面,這個時候就涉
及到問題的處理。我們知道目前流行的動態(tài)網(wǎng)頁技術(shù)例如ASP、JSP無不是通過來處理會話信息的。為了使我們的程序能使用別人所提供的服務(wù)頁面,就要求程
序首先登錄后再訪問服務(wù)頁面,這過程就需要自行處理,想想當(dāng)你用java.net.HttpURLConnection來完成這些功能時是多么恐怖的事情
啊!況且這僅僅是我們所說的頑固的WEB服務(wù)器中的一個很常見的“頑固”!再有如通過HTTP來上傳文件呢?不需要頭疼,這些問題有了“它”就很容易解決
了!
我們不可能列舉所
有可能的頑固,我們會針對幾種最常見的問題進(jìn)行處理。當(dāng)然了,正如前面說到的,如果我們自己使用java.net.HttpURLConnection來
搞定這些問題是很恐怖的事情,因此在開始之前我們先要介紹一下一個開放源碼的項(xiàng)目,這個項(xiàng)目就是Apache開源組織中的httpclient,它隸屬于
Jakarta的commons項(xiàng)目,目前的版本是2.0RC2。commons下本來已經(jīng)有一個net的子項(xiàng)目,但是又把httpclient單獨(dú)提出
來,可見http服務(wù)器的訪問絕非易事。
Commons-httpclient
項(xiàng)目就是專門設(shè)計(jì)來簡化HTTP客戶端與服務(wù)器進(jìn)行各種通訊編程。通過它可以讓原來很頭疼的事情現(xiàn)在輕松的解決,例如你不再管是HTTP或者HTTPS的
通訊方式,告訴它你想使用HTTPS方式,剩下的事情交給httpclient替你完成。本文會針對我們在編寫HTTP客戶端程序時經(jīng)常碰到的幾個問題進(jìn)
行分別介紹如何使用httpclient來解決它們,為了讓讀者更快的熟悉這個項(xiàng)目我們最開始先給出一個簡單的例子來讀取一個網(wǎng)頁的內(nèi)容,然后循序漸進(jìn)解
決掉前進(jìn)中的所有問題。
1. 讀取網(wǎng)頁(HTTP/HTTPS)內(nèi)容
下面是我們給出的一個簡單的例子用來訪問某個頁面
/*
* 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();
//設(shè)置代理服務(wù)器地址和端口
//client.getHostConfiguration().setProxy("proxy_host_addr",proxy_port);
//使用GET方法,如果服務(wù)器需要通過HTTPS連接,那只需要將下面URL中的http換成https
HttpMethod method = new GetMethod("http://java.sun.com");
//使用POST方法
//HttpMethod method = new PostMethod("http://java.sun.com");
client.executeMethod(method);
//打印服務(wù)器返回的狀態(tài)
System.out.println(method.getStatusLine());
//打印返回的信息
System.out.println(method.getResponseBodyAsString());
//釋放連接
method.releaseConnection();
}
}
在這個例子中首先創(chuàng)建一個
HTTP客戶端(HttpClient)的實(shí)例,然后選擇提交的方法是GET或者POST,最后在HttpClient實(shí)例上執(zhí)行提交的方法,最后從所選
擇的提交方法中讀取服務(wù)器反饋回來的結(jié)果。這就是使用HttpClient的基本流程。其實(shí)用一行代碼也就可以搞定整個請求的過程,非常的簡單!
2. 以GET或者POST方式向網(wǎng)頁提交參數(shù)
其實(shí)前面一個最簡單的示例中我們已經(jīng)介紹了如何使用GET或者POST方式來請求一個頁面,本小節(jié)與之不同的是多了提交時設(shè)定頁面所需的參數(shù),我們
知道如果是GET的請求方式,那么所有參數(shù)都直接放到頁面的URL后面用問號與頁面地址隔開,每個參數(shù)用&隔開,例如:http://java.sun.com?name=liudong&mobile=123456,但是當(dāng)使用POST方法時就會稍微有一點(diǎn)點(diǎn)麻煩。本小節(jié)的例子演示向如何查詢手機(jī)號碼所在的城市,代碼如下:
/*
* 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.*;
/**
* 提交參數(shù)演示
* 該程序連接到一個用于查詢手機(jī)號碼所屬地的頁面
* 以便查詢號碼段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方式提交數(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");
NamePair simcard = new NamePair("simcard","1330227");
post.setRequestBody(new NamePair[] { simcard});
return post;
}
}
在上面的例子中頁面http://www.imobile.com.cn/simcard.php需要一個參數(shù)是simcard,這個參數(shù)值為手機(jī)號碼段,即手機(jī)號碼的前七位,服務(wù)器會返回提交的手機(jī)號碼對應(yīng)的省份、城市以及其他詳細(xì)信息。GET的提交方法只需要在URL后加入?yún)?shù)信息,而POST則需要通過NamePair類來設(shè)置參數(shù)名稱和它所對應(yīng)的值
3. 處理頁面重定向
在JSP/Servlet編程中response.sendRedirect方法就是使用HTTP協(xié)議中的重定向機(jī)制。它與JSP中的<
jsp:forward
…>的區(qū)別在于后者是在服務(wù)器中實(shí)現(xiàn)頁面的跳轉(zhuǎn),也就是說應(yīng)用容器加載了所要跳轉(zhuǎn)的頁面的內(nèi)容并返回給客戶端;而前者是返回一個狀態(tài)碼,這些狀態(tài)碼
的可能值見下表,然后客戶端讀取需要跳轉(zhuǎn)到的頁面的URL并重新加載新的頁面。就是這樣一個過程,所以我們編程的時候就要通過
HttpMethod.getStatusCode()方法判斷返回值是否為下表中的某個值來判斷是否需要跳轉(zhuǎn)。如果已經(jīng)確認(rèn)需要進(jìn)行頁面跳轉(zhuǎn)了,那么可
以通過讀取HTTP頭中的location屬性來獲取新的地址。