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