原文出處--------http://hi.baidu.com/wader2006/blog/item/7e7b3a291f7801fd99250a91.html
雖然用telnet這樣的程序都可把頁面取回來,但是在與web服務(wù)器的交互中,如果涉及cookie或https或ssl等內(nèi)容,一般功能相對完備的http客戶端還是非常必要的。IE或NetScape等瀏覽器確實不錯,可是如果為實現(xiàn)持續(xù)互動而在程序調(diào)用瀏覽器,我個人認為其中的工作量還是不小的,這還沒考慮版權(quán)問題。最好的辦法,就是能有一個開源的包,能實現(xiàn)http客戶端的功能,供我們開發(fā)的程序調(diào)用。httpclient就是這么一個包,我相信可能有比它的實現(xiàn)更好的,但目前我只關(guān)注這個。:)
下面是nogoop做的功能比較表:
Features | nogoop | Sun JRE < 1.4.2 | Sun JRE 1.4.2 | Innovation | Apache/Jakarta |
cookies | X | X | |||
plug compatible | X | X | X | X | [partial] |
true request output stream | X | X | |||
true response input stream | X | X | X | ||
connection keep alive | X | X | X | X | X |
connection pool throttling | X | X | |||
connection/request timeout | X | X [uns] | X | X | |
idle connection timeout | X | X | |||
pipelining of requests | X | ||||
alternate DNS resolution (dnsjava) | X | ||||
SSL | X | X | X | X | X |
basic authentication | X | X | X | X | X |
digest authentication | X | X | X | X | X |
NTLM authentication | X | [Windows only] | X | ||
proxy authentication | X | X | X | X | X |
minimum JRE version | 1.2 | 1 | 01年4月2日 | 1.2 | 1.2 |
price | $499 | free | free | free | free |
source available | X | X | X | ||
diagnostic tracing | X | X | X | ||
actively supported | X | X | X | X | |
fix turnaround | fast | slow | slow | none | medium |
license | purchase | Sun JRE | Sun JRE | LGPL | Apache |
1、HttpClient的功能
- 基于標準,純正java,實現(xiàn)了http1.0和1.1。
- 在一個可擴展的OO框架內(nèi),實現(xiàn)了HTTP的全部方法(GET, POST,
PUT, DELETE, HEAD, OPTIONS, and TRACE) - 支持HTTPS(ssl上的HTTP)的加密操作
- 透明地穿過HTTP代理建立連接
- 通過CONNECT方法,利用通過建立穿過HTTP代理的HTTPS連接
- 利用本地Java socket,透明地穿過SOCKS(版本5和4)代理建立連接
- 支持利用Basic、Digest和NTLM加密的認證
- 支持用于上傳大文件的Multi-Part表單POST方法
- 插件式安全socket實現(xiàn),易于使用第三方的解決方案
- 連接管理,支持多線程應(yīng)用,支持設(shè)定單個主機總連接和最高連接數(shù)量,自動檢測和關(guān)閉失效連接
- 直接將請求信息流送到服務(wù)器的端口
- 直接讀取從服務(wù)器的端口送出的應(yīng)答信息
- 支持HTTP/1.0中用KeepAlive和HTTP/1.1中用persistance設(shè)置的持久連接
- 直接訪問由服務(wù)器送出的應(yīng)答代碼和頭部信息
- 可設(shè)置連接超時時間
- HttpMethods 實現(xiàn)Command Pattern,以允許并行請求或高效連接復(fù)用
- 遵循the Apache Software License協(xié)議,源碼免費可得
2、預(yù)備工作
對jre1.3.*,如果要HttpClient支持https,則需要下載并安裝jsse和jce.安裝的步驟如下:
1)下載jsse和jce.
2)檢查CLASSPATH中沒有與jsse和jce相關(guān)的jar包
3)將 US_export_policy.jar、local_policy.jar、jsse.jar、jnet.jar、jce1_2_x.jar、sunjce_provider.jar、jcert.jar復(fù)制到目錄:
UNIX:$JDK_HOME/jre/lib/ext
Windows:%JDK_HOME%\jre\lib\ext
4)修改下述目錄下的java.security文件。
UNIX:$JDK_HOME/jre/lib/security/
Windows:%JDK_HOME%\jre\lib\security\
5)
#
# List of providers and their preference orders:
#
security.provider.1=sun.security.provider.Sun
security.provider.2=com.sun.rsajca.Provider
改為:
#
# List of providers and their preference orders:
#
security.provider.1=com.sun.crypto.provider.SunJCE
security.provider.2=sun.security.provider.Sun
security.provider.3=com.sun.rsajca.Provider
security.provider.4=com.sun.net.ssl.internal.ssl.Provider
HttpClient還要求安裝commons-logging,下面跟httpclient一塊安裝。
3、取得源碼
password: anoncvs
cvs -d :pserver:anoncvs@cvs.apache.org:/home/cvspublic checkout jakarta-commons/logging
cvs -d :pserver:anoncvs@cvs.apache.org:/home/cvspublic checkout jakarta-commons/httpclient
編譯:
ant dist
cp dis/*.jar ../httpclient/lib/
cd ../httpclient
ant dist
4、使用HttpClient編程的基本步聚
- 創(chuàng)建 HttpClient 的一個實例.
- 創(chuàng)建某個方法(DeleteMethod,EntityEnclosingMethod,ExpectContinueMethod,GetMethod,HeadMethod,MultipartPostMethod,OptionsMethod,PostMethod,PutMethod,TraceMethod)的一個實例,一般可用要目標URL為參數(shù)。
- 讓 HttpClient 執(zhí)行這個方法.
- 讀取應(yīng)答信息.
- 釋放連接.
- 處理應(yīng)答.
在執(zhí)行方法的過程中,有兩種異常,一種是HttpRecoverableException,表示偶然性錯誤發(fā)生,一般再試可能成功,另一種是IOException,嚴重錯誤。
這兒有這個教程中的一個例程,可以下載。
5、認證
HttpClient三種不同的認證方案: Basic, Digest and NTLM. 這些方案可用于服務(wù)器或代理對客戶端的認證,簡稱服務(wù)器認證或代理認證。
1)服務(wù)器認證(Server Authentication)
HttpClient處理服務(wù)器認證幾乎是透明的,僅需要開發(fā)人員提供登錄信息(login credentials)。登錄信息保存在HttpState類的實例中,可以通過 setCredentials(String realm, Credentials cred)和getCredentials(String realm)來獲取或設(shè)置。注意,設(shè)定對非特定站點訪問所需要的登錄信息,將realm參數(shù)置為null. HttpClient內(nèi)建的自動認證,可以通過HttpMethod類的setDoAuthentication(boolean doAuthentication)方法關(guān)閉,而且這次關(guān)閉只影響HttpMethod當前的實例。
搶先認證(Preemptive Authentication)可以通過下述方法打開.
在這種模式時,HttpClient會主動將basic認證應(yīng)答信息傳給服務(wù)器,即使在某種情況下服務(wù)器可能返回認證失敗的應(yīng)答,這樣做主要是為了減少連接的建立。為使每個新建的 HttpState實例都實行搶先認證,可以如下設(shè)置系統(tǒng)屬性。
Httpclient實現(xiàn)的搶先認證遵循rfc2617.
2)代理認證(proxy authentication)
除了登錄信息需單獨存放以外,代理認證與服務(wù)器認證幾乎一致。用 setProxyCredentials(String realm, Credentials cred)和 getProxyCredentials(String realm)設(shè)、取登錄信息。
3)認證方案(authentication schemes)
Basic
是HTTP中規(guī)定最早的也是最兼容(?)的方案,遺憾的是也是最不安全的一個方案,因為它以明碼傳送用戶名和密碼。它要求一個UsernamePasswordCredentials實例,可以指定服務(wù)器端的訪問空間或采用默認的登錄信息。
Digest
是在HTTP1.1中增加的一個方案,雖然不如Basic得到的軟件支持多,但還是有廣泛的使用。Digest方案比Basic方案安全得多,因它根本就不通過網(wǎng)絡(luò)傳送實際的密碼,傳送的是利用這個密碼對從服務(wù)器傳來的一個隨機數(shù)(nonce)的加密串。它要求一個UsernamePasswordCredentials實例,可以指定服務(wù)器端的訪問空間或采用默認的登錄信息。
NTLM
這是HttpClient支持的最復(fù)雜的認證協(xié)議。它M$設(shè)計的一個私有協(xié)議,沒有公開的規(guī)范說明。一開始由于設(shè)計的缺陷,NTLM的安全性比Digest差,后來經(jīng)過一個ServicePack補丁后,安全性則比較Digest高。NTLM需要一個NTCredentials實例. 注意,由于NTLM不使用訪問空間(realms)的概念,HttpClient利用服務(wù)器的域名作訪問空間的名字。還需要注意,提供給NTCredentials的用戶名,不要用域名的前綴 - 如: "adrian" 是正確的,而 "DOMAIN\adrian" 則是錯的.
NTLM認證的工作機制與basic和digest有很大的差別。這些差別一般由HttpClient處理,但理解這些差別有助避免在使用NTLM認證時出現(xiàn)錯誤。
- 從HttpClientAPI的角度來看,NTLM與其它認證方式一樣的工作,差別是需要提供'NTCredentials'實例而不是'UsernamePasswordCredentials'(其實,前者只是擴展了后者)
- 對NTLM認證,訪問空間是連接到的機器的域名,這對多域名主機會有一些麻煩.只有HttpClient連接中指定的域名才是認證用的域名。建議將realm設(shè)為null以使用默認的設(shè)置。
- NTLM只是認證了一個連接而不是一請求,所以每當一個新的連接建立就要進行一次認證,且在認證的過程中保持連接是非常重要的。 因此,NTLM不能同時用于代理認證和服務(wù)器認證,也不能用于http1.0連接或服務(wù)器不支持持久連接的情況。
6、重定向
由于技術(shù)限制,以及為保證2.0發(fā)布版API的穩(wěn)定,HttpClient還不能自動處重定向,但對重定向到同一主機、同一端口且采用同一協(xié)議的情況HttpClient可以支持。不能自動的處理的情況,包括需要人工交互的情況,或超出httpclient的能力。
當服務(wù)器重定向指令指到不同的主機時,HttpClient只是簡單地將重定向狀態(tài)碼作為應(yīng)答狀態(tài)。所有的300到399(包含兩端)的返回碼,都表示是重定向應(yīng)答。常見的有:
- 301 永久移動. HttpStatus.SC_MOVED_PERMANENTLY
- 302 臨時移動. HttpStatus.SC_MOVED_TEMPORARILY
- 303 See Other. HttpStatus.SC_SEE_OTHER
- 307 臨時重定向. HttpStatus.SC_TEMPORARY_REDIRECT
當收到簡單的重定向時,程序應(yīng)從HttpMethod對象中抽取新的URL并將其下載。另外,限制一下重定向次數(shù)是個好的主意,這可以避免遞歸循環(huán)。新的URL可以從頭字段Location中抽取,如下:
Header locationHeader = method.getResponseHeader("location");
if (locationHeader != null) {
redirectLocation = locationHeader.getValue();
} else {
// The response is invalid and did not provide the new location for
// the resource. Report an error or possibly handle the response
// like a 404 Not Found error.
}
特殊重定向:
- 300 多重選擇. HttpStatus.SC_MULTIPLE_CHOICES
- 304 沒有改動. HttpStatus.SC_NO T_MODIFIED
- 305 使用代理. HttpStatus.SC_USE_PROXY
7、字符編碼(character encoding)
一個HTTP協(xié)議的請求或應(yīng)答的頭部(在http協(xié)議中,數(shù)據(jù)包分為兩部分,一部分是頭部,由一些名值對構(gòu)成,一部分是主體(body),是真正傳辦理的數(shù)據(jù)(如HTML頁面等)),必須以US-ASCII編碼,這是因為頭部不傳數(shù)據(jù)而只描述被要傳輸?shù)臄?shù)據(jù)的一些信息,一個例外是cookie,它是數(shù)據(jù)但是通過頭部進行傳輸?shù)模运惨肬S-ASCII編碼。
HTTP數(shù)據(jù)包的主體部分,可以用任何一種方式進行編碼,默認是ISO-8859-1,具體可以用頭部字段Content-Type指定。可以利用 addRequestHeader方法,設(shè)定編碼方式;用 getResponseCharSet取得編碼方式。對HTML或XML等類型的文檔,它們的本身的Content-Type也可以指定編碼方式,主要區(qū)分兩者的作用范圍以得到正確實的解碼。
URL的編碼標準,由RFC1738指定為,只能是由可打印8位/字節(jié)的us-ascii字符組成,80-ff不是us-ascii字符,而00-1F是控制字符,這兩個區(qū)域中用的字符都須加以編碼(encoded)。
8、Cookies
HttpClient能自動管理cookie,包括允許服務(wù)器設(shè)置cookie并在需要的時候自動將cookie返回服務(wù)器,它也支持手工設(shè)置cookie后發(fā)送到服務(wù)器端。不幸的是,對如何處理cookie,有幾個規(guī)范互相沖突:Netscape Cookie 草案, RFC2109, RFC2965,而且還有很大數(shù)量的軟件商的cookie實現(xiàn)不遵循任何規(guī)范. 為了處理這種狀況,HttpClient提供了策略驅(qū)動的cookie管理方式。HttpClient支持的cookie規(guī)范有:
- Netscape cookie草案,是最早的cookie規(guī)范,基于rfc2109。盡管這個規(guī)范與rc2109有較大的差別,這樣做可以與一些服務(wù)器兼容。
- rfc2109,是w3c發(fā)布的第一個官方cookie規(guī)范。理論上講,所有的服務(wù)器在處理cookie(版本1)時,都要遵循此規(guī)范,正因如此,HttpClient將其設(shè)為默認的規(guī)范。遺憾的是,這個規(guī)范太嚴格了,以致很多服務(wù)器不正確的實施了該規(guī)范或仍在作用Netscape規(guī)范。在這種情況下,應(yīng)使用兼容規(guī)范。
- 兼容性規(guī)范,設(shè)計用來兼容盡可能多的服務(wù)器,即使它們并沒有遵循標準規(guī)范。當解析cookie出現(xiàn)問題時,應(yīng)考慮采用兼容性規(guī)范。
RFC2965規(guī)范暫時沒有被HttpClient支持(在以后的版本為會加上),它定義了cookie版本2,并說明了版本1cookie的不足,RFC2965有意有久取代rfc2109.
在HttpClient中,有兩種方法來指定cookie規(guī)范的使用,
-
HttpClient client = new HttpClient();這種方法設(shè)置的規(guī)范只對當前的HttpState有效,參數(shù)可取值CookiePolicy.COMPATIBILITY,CookiePolicy.NETSCAPE_DRAFT或CookiePolicy.RFC2109。
client.getState().setCookiePolicy(CookiePolicy.COMPATIBILITY); -
System.setProperty("apache.commons.httpclient.cookiespec", "COMPATIBILITY");此法指的規(guī)范,對以后每個新建立的HttpState對象都有效,參數(shù)可取值"COMPATIBILITY","NETSCAPE_DRAFT"或"RFC2109"。
常有不能解析cookie的問題,但更換到兼容規(guī)范大都能解決。
9、使用HttpClient遇到問題怎么辦?
- 用一個瀏覽器訪問服務(wù)器,以確認服務(wù)器應(yīng)答正常
- 如果在使代理,關(guān)掉代理試試
- 另找一個服務(wù)器來試試(如果運行著不同的服務(wù)器軟件更好)
- 檢查代碼是否按教程中講的思路編寫
- 設(shè)置log級別為debug,找出問題出現(xiàn)的原因
- 打開wiretrace,來追蹤客戶端與服務(wù)器的通信,以確實問題出現(xiàn)在什么地方
- 用telnet或netcat手工將信息發(fā)送到服務(wù)器,適合于猜測已經(jīng)找到了原因而進行試驗時
- 將netcat以監(jiān)聽方式運行,用作服務(wù)器以檢查httpclient如何處理應(yīng)答的。
- 利用最新的httpclient試試,bug可能在最新的版本中修復(fù)了
- 向郵件列表求幫助
- 向bugzilla報告bug.
10、SSL
借助Java Secure Socket Extension (JSSE),HttpClient全面支持Secure Sockets Layer (SSL)或IETF Transport Layer Security (TLS)協(xié)議上的HTTP。JSSE已經(jīng)jre1.4及以后的版本中,以前的版本則需要手工安裝設(shè)置,具體過程參見Sun網(wǎng)站或本學習筆記。
HttpClient中使用SSL非常簡單,參考下面兩個例子:
GetMethod httpget = new GetMethod("https://www.verisign.com/");
httpclient.executeMethod(httpget);
System.out.println(httpget.getStatusLine().toString());
,如果通過需要授權(quán)的代理,則如下:
httpclient.getHostConfiguration().setProxy("myproxyhost", 8080);
httpclient.getState().setProxyCredentials("my-proxy-realm", " myproxyhost",
new UsernamePasswordCredentials("my-proxy-username", "my-proxy-password"));
GetMethod httpget = new GetMethod("https://www.verisign.com/");
httpclient.executeMethod(httpget);
System.out.println(httpget.getStatusLine().toString());
在HttpClient中定制SSL的步驟如下:
- 提供了一個實現(xiàn)了org.apache.commons.httpclient.protocol.SecureProtocolSocketFactory接口的socket factory。這個 socket factory負責打一個到服務(wù)器的端口,使用標準的或第三方的SSL函數(shù)庫,并進行象連接握手等初始化操作。通常情況下,這個初始化操作在端口被創(chuàng)建時自動進行的。
- 實例化一個org.apache.commons.httpclient.protocol.Protocol對象。創(chuàng)建這個實例時,需要一個合法的協(xié)議類型(如https),一個定制的socket factory,和一個默認的端中號(如https的443端口).
Protocol myhttps = new Protocol("https", new MySSLSocketFactory(), 443);然后,這個實例可被設(shè)置為協(xié)議的處理器。HttpClient httpclient = new HttpClient();
httpclient.getHostConfiguration().setHost("www.whatever.com", 443, myhttps);
GetMethod httpget = new GetMethod("/");
httpclient.executeMethod(httpget); - 通過調(diào)用Protocol.registerProtocol方法,將此定制的實例,注冊為某一特定協(xié)議的默認的處理器。由此,可以很方便地定制自己的協(xié)議類型(如myhttps)。
Protocol.registerProtocol("myhttps",如果想用自己定制的處理器取代https默認的處理器,只需要將其注冊為"https"即可。
new Protocol("https", new MySSLSocketFactory(), 9443));
...
HttpClient httpclient = new HttpClient();
GetMethod httpget = new GetMethod("myhttps://www.whatever.com/");
httpclient.executeMethod(httpget);Protocol.registerProtocol("https",
new Protocol("https", new MySSLSocketFactory(), 443));
HttpClient httpclient = new HttpClient();
GetMethod httpget = new GetMethod("https://www.whatever.com/");
httpclient.executeMethod(httpget);
已知的限制和問題
- 持續(xù)的SSL連接在Sun的低于1.4JVM上不能工作,這是由于JVM的bug造成。
- 通過代理訪問服務(wù)器時,非搶先認證( Non-preemptive authentication)會失敗,這是由于HttpClient的設(shè)計缺陷造成的,以后的版本中會修改。
遇到問題的處理
很多問題,特別是在jvm低于1.4時,是由jsse的安裝造成的。
下面的代碼,可作為最終的檢測手段。
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.io.Writer;
import java.net.Socket; import javax.net.ssl.SSLSocketFactory; public class Test {
public static final String TARGET_HTTPS_SERVER = "www.verisign.com";
public static final int TARGET_HTTPS_PORT = 443;
public static void main(String[] args) throws Exception {
Socket socket = SSLSocketFactory.getDefault().
createSocket(TARGET_HTTPS_SERVER, TARGET_HTTPS_PORT);
try {
Writer out = new OutputStreamWriter(
socket.getOutputStream(), "ISO-8859-1");
out.write("GET / HTTP/1.1\r\n");
out.write("Host: " + TARGET_HTTPS_SERVER + ":" +
TARGET_HTTPS_PORT + "\r\n");
out.write("Agent: SSL-TEST\r\n");
out.write("\r\n");
out.flush();
BufferedReader in = new BufferedReader(
new InputStreamReader(socket.getInputStream(), "ISO-8859-1"));
String line = null;
while ((line = in.readLine()) != null) {
System.out.println(line);
}
} finally {
socket.close();
}
}
}
1、httpclient的多線程處理
使用多線程的主要目的,是為了實現(xiàn)并行的下載。在httpclient運行的過程中,每個http協(xié)議的方法,使用一個HttpConnection實例。由于連接是一種有限的資源,每個連接在某一時刻只能供一個線程和方法使用,所以需要確保在需要時正確地分配連接。HttpClient采用了一種類似jdbc連接池的方法來管理連接,這個管理工作由 MultiThreadedHttpConnectionManager完成。
new MultiThreadedHttpConnectionManager();
HttpClient client = new HttpClient(connectionManager);
此是,client可以在多個線程中被用來執(zhí)行多個方法。每次調(diào)用HttpClient.executeMethod() 方法,都會去鏈接管理器申請一個連接實例,申請成功這個鏈接實例被簽出(checkout),隨之在鏈接使用完后必須歸還管理器。管理器支持兩個設(shè)置:
maxConnectionsPerHost | 每個主機的最大并行鏈接數(shù),默認為2 |
maxTotalConnections | 客戶端總并行鏈接最大數(shù),默認為20 |
管理器重新利用鏈接時,采取早歸還者先重用的方式(least recently used approach)。
由于是使用HttpClient的程序而不是HttpClient本身來讀取應(yīng)答包的主體,所以HttpClient無法決定什么時間連接不再使用了,這也就要求在讀完應(yīng)答包的主體后必須手工顯式地調(diào)用releaseConnection()來釋放申請的鏈接。
HttpClient client = new HttpClient(connectionManager);
...
// 在某個線程中。
GetMethod get = new GetMethod("http://jakarta.apache.org/");
try {
client.executeMethod(get);
// print response to stdout
System.out.println(get.getResponseBodyAsStream());
} finally {
// be sure the connection is released back to the connection
// manager
get.releaseConnection();
}
對每一個HttpClient.executeMethod須有一個method.releaseConnection()與之匹配.
12、HTTP方法
HttpClient支持的HTTP方法有8種,下面分述之。
1、Options
HTTP方法Options用來向服務(wù)器發(fā)送請求,希望獲得針對由請求URL(request url)標志的資源在請求/應(yīng)答的通信過程可以使用的功能選項。通過這個方法,客戶端可以在采取具體行動之前,就可對某一資源決定采取什么動作和/或以及一些必要條件,或者了解服務(wù)器提供的功能。這個方法最典型的應(yīng)用,就是用來獲取服務(wù)器支持哪些HTTP方法。
HttpClient中有一個類叫OptionsMethod,來支持這個HTTP方法,利用這個類的getAllowedMethods方法,就可以很簡單地實現(xiàn)上述的典型應(yīng)用。
// 執(zhí)行方法并做相應(yīng)的異常處理
...
Enumeration allowedMethods = options.getAllowedMethods();
options.releaseConnection();
2、Get
HTTP方法GET用來取回請求URI(request-URI)標志的任何信息(以實體(entity)的形式),"get"這個單詞本意就是”獲取“的意思。如果請求URI指向的一個數(shù)據(jù)處理過程,那這個過程生成的數(shù)據(jù),在應(yīng)答中以實體的形式被返回,而不是將這個過程的代碼的返回。
如果HTTP包中含有If-ModifiedSince, If-Unmodified-Since, If-Match, If-None-Match, 或 If-Range等頭字段,則GET也就變成了”條件GET“,即只有滿足上述字段描述的條件的實體才被取回,這樣可以減少一些非必需的網(wǎng)絡(luò)傳輸,或者減少為獲取某一資源的多次請求(如第一次檢查,第二次下載)。(一般的瀏覽器,都有一個臨時目錄,用來緩存一些網(wǎng)頁信息,當再次瀏覽某個頁面的時候,只下載那些修改過的內(nèi)容,以加快瀏覽速度,就是這個道理。至于檢查,則常用比GET更好的方法HEAD來實現(xiàn)。)如果HTTP包中含有Range頭字段,那么請求URI指定的實體中,只有決定范圍條件的那部分才被取回來。(用過多線程下載工具的朋友,可能比較容易理解這一點)
這個方法的典型應(yīng)用,用來從web服務(wù)器下載文檔。HttpClient定義了一個類叫GetMethod來支持這個方法,用GetMethod類中g(shù)etResponseBody, getResponseBodyAsStream 或 getResponseBodyAsString函數(shù)就可以取到應(yīng)答包包體中的文檔(如HTML頁面)信息。這這三個函數(shù)中,getResponseBodyAsStream通常是最好的方法,主要是因為它可以避免在處理下載的文檔之前緩存所有的下載的數(shù)據(jù)。
// 執(zhí)行方法,并處理失敗的請求.
...
InputStream in = get.getResponseBodyAsStream();
// 利用輸入流來處理信息。
get.releaseConnection();
對GetMethod的最常見的不正確的使用,是沒有將全部的應(yīng)答主體的數(shù)據(jù)讀出來。還有,必須注意要手工明確地將鏈接釋放。
3、Head
HTTP的Head方法,與Get方法完全一致,唯一的差別是服務(wù)器不能在應(yīng)答包中包含主體(message-body),而且一定不能包含主體。使用這個方法,可以使得客戶無需將資源下載回就可就以得到一些關(guān)于它的基本信息。這個方法常用來檢查超鏈的可訪問性以及資源最近有沒有被修改。
HTTP的head方法最典型的應(yīng)用,是獲取資源的基本信息。HttpClient定義了HeadMethod類支持這個方法,HeadMethod類與其它*Method類一樣,用 getResponseHeaders()取回頭部信息,而沒有自己的特殊方法。
// 執(zhí)行方法,并處理失敗的請求.
...
// 取回應(yīng)答包的頭字段信息.
Header[] headers = head.getResponseHeaders(); // 只取回最后修改日期字段的信息.
String lastModified = head.getResponseHeader("last-modified").getValue();
4、Post
Post在英文有“派駐”的意思,HTTP方法POST就是要求服務(wù)器接受請求包中的實體,并將其作為請求URI的下屬資源。從本質(zhì)上說,這意味著服務(wù)器要保存這個實體信息,而且通常由服務(wù)器端的程序進行處理。Post方法的設(shè)計意圖,是要以一種統(tǒng)一的方式實現(xiàn)下列功能:
- 對已有的資源做評注
- 將信息發(fā)布到BBS、新聞組、郵件列表,或類似的文章組中
- 將一塊數(shù)據(jù),提交給數(shù)據(jù)處理進程
- 通過追加操作,來擴展一個數(shù)據(jù)庫
這些都操作期待著在服務(wù)器端產(chǎn)生一定的“副作用”,如修改了數(shù)據(jù)庫等。
HttpClient定義PostMethod類以支持該HTTP方法,在httpclient中,使用post方法有兩個基本的步驟:為請求包準備數(shù)據(jù),然后讀取服務(wù)器來的應(yīng)答包的信息。通過調(diào)用 setRequestBody()函數(shù),來為請求包提供數(shù)據(jù),它可以接收三類參數(shù):輸入流、名值對數(shù)組或字符串。至于讀取應(yīng)答包需要調(diào)用 getResponseBody* 那一系列的方法,與GET方法處理應(yīng)答包的方法相同。
常見問題是,沒有將全部應(yīng)答讀取(無論它對程序是否有用),或沒有釋放鏈接資源。