# httpclient2
<div><div style="color:#333333;font-family:Verdana, Arial, Tahoma, sans-serif;font-size:large;font-weight:bold;"><span style="font-size:19px;">第二章 連接管理</span></div><div style="color:#333333;font-family:Verdana, Arial, Tahoma, sans-serif;font-size:9.5pt;"><p style="color:inherit;font-family:inherit;font-size:inherit;font-style:inherit;">HttpClient有一個對連接初始化和終止,還有在活動連接上I/O操作的完整控制。而連接操作的很多方面可以使用一些參數來控制。</p><h3>2.1 連接參數</h3><p style="color:inherit;font-family:inherit;font-size:inherit;font-style:inherit;">這些參數可以影響連接操作:</p><ul><li>'http.socket.timeout':
定義了套接字的毫秒級超時時間(SO_TIMEOUT),這就是等待數據,換句話說,在兩個連續的數據包之間最大的閑置時間。如果超時時間是0就解釋為是
一個無限大的超時時間。這個參數期望得到一個java.lang.Integer類型的值。如果這個參數沒有被設置,那么讀取操作就不會超時(無限大的超
時時間)。</li><li>'http.tcp.nodelay':
決定了是否使用Nagle算法。Nagle算法視圖通過最小化發送的分組數量來節省帶寬。當應用程序希望降低網絡延遲并提高性能時,它們可以關閉
Nagle算法(也就是開啟TCP_NODELAY)。數據將會更早發送,增加了帶寬消耗的成文。這個參數期望得到一個
java.lang.Boolean類型的值。如果這個參數沒有被設置,那么TCP_NODELAY就會開啟(無延遲)。</li><li>'http.socket.buffer-
size':決定了內部套接字緩沖使用的大小,來緩沖數據同時接收/傳輸HTTP報文。這個參數期望得到一個java.lang.Integer類型的
值。如果這個參數沒有被設置,那么HttpClient將會分配8192字節的套接字緩存。</li><li>'http.socket.linger':
使用指定的秒數拖延時間來設置SO_LINGER。最大的連接超時值是平臺指定的。值0暗示了這個選項是關閉的。值-1暗示了使用了JRE默認的。這個設
置僅僅影響套接字關閉操作。如果這個參數沒有被設置,那么就假設值為-1(JRE默認)。</li><li>'http.connection.timeout':
決定了直到連接建立時的毫秒級超時時間。超時時間的值為0解釋為一個無限大的時間。這個參數期望得到一個java.lang.Integer類型的值。如
果這個參數沒有被設置,連接操作將不會超時(無限大的超時時間)。</li><li>'http.connection.stalecheck':
決定了是否使用舊的連接檢查。當在一個連接之上執行一個請求而服務器端的連接已經關閉時,關閉舊的連接檢查可能導致在獲得一個I/O錯誤風險時顯著的性能
提升(對于每一個請求,檢查時間可以達到30毫秒)。這個參數期望得到一個java.lang.Boolean類型的值。出于性能的關鍵操作,檢查應該被
關閉。如果這個參數沒有被設置,那么舊的連接將會在每個請求執行之前執行。</li><li>'http.connection.max-
line-length':決定了最大請求行長度的限制。如果設置為一個正數,任何HTTP請求行超過這個限制將會引發
java.io.IOException異常。負數或零將會關閉這個檢查。這個參數期望得到一個java.lang.Integer類型的值。如果這個參
數沒有被設置,那么就不強制進行限制了。</li><li>'http.connection.max-
header-count':決定了允許的最大HTTP頭部信息數量。如果設置為一個正數,從數據流中獲得的HTTP頭部信息數量超過這個限制就會引發
java.io.IOException異常。負數或零將會關閉這個檢查。這個參數期望得到一個java.lang.Integer類型的值。如果這個參
數沒有被設置,那么就不</li><li>強制進行限制了。</li><li>'http.connection.max-
status-line-garbage':決定了在期望得到HTTP響應狀態行之前可忽略請求行的最大數量。使用HTTP/1.1持久性連接,這個問題
產生的破碎的腳本將會返回一個錯誤的Content-Length(有比指定的字節更多的發送)。不幸的是,在某些情況下,這個不能在錯誤響應后來偵測,
只能在下一次之前。所以HttpClient必須以這種方式跳過那些多余的行。這個參數期望得到一個java.lang.Integer類型的值。0是不
允許在狀態行之前的所有垃圾/空行。使用java.lang.Integer#MAX_VALUE來設置不限制的數字。如果這個參數沒有被設置那就假設是
不限制的。</li></ul><h3>2.2 持久連接</h3><p style="color:inherit;font-family:inherit;font-size:inherit;font-style:inherit;">從一個主機向另外一個建立連接的過程是相當復雜的,而且包含了兩個終端之間的很多包的交換,它是相當費時的。連接握手的開銷是很重要的,特別是對小量的HTTP報文。如果打開的連接可以被重用來執行多次請求,那么就可以達到很高的數據吞吐量。</p><p style="color:inherit;font-family:inherit;font-size:inherit;font-style:inherit;">HTTP/1.1
強調HTTP連接默認情況可以被重用于多次請求。HTTP/1.0兼容的終端也可以使用相似的機制來明確地交流它們的偏好來保證連接處于活動狀態,也使用
它來處理多個請求。HTTP代理也可以保持空閑連接處于一段時間的活動狀態,防止對相同目標主機的一個連接也許對隨后的請求需要。保持連接活動的能力通常
被稱作持久性連接。HttpClient完全支持持久性連接。</p><h3>2.3 HTTP連接路由</h3><p style="color:inherit;font-family:inherit;font-size:inherit;font-style:inherit;">HttpClient能夠直接或通過路由建立連接到目標主機,這會涉及多個中間連接,也被稱為跳。HttpClient區分路由和普通連接,通道和分層。通道連接到目標主機的多個中間代理的使用也稱作是代理鏈。</p><p style="color:inherit;font-family:inherit;font-size:inherit;font-style:inherit;">普通路由由連接到目標或僅第一次的代理來創建。通道路由通過代理鏈到目標連接到第一通道來建立。沒有代理的路由不是通道的,分層路由通過已存在連接的分層協議來建立。協議僅僅可以在到目標的通道上或在沒有代理的直接連接上分層。</p><h4>2.3.1 路由計算</h4><p style="color:inherit;font-family:inherit;font-size:inherit;font-style:inherit;">RouteInfo
接口代表關于最終涉及一個或多個中間步驟或跳的目標主機路由的信息。HttpRoute是RouteInfo的具體實現,這是不能改變的(是不變的)。
HttpTracker是可變的RouteInfo實現,由HttpClient在內部使用來跟蹤到最大路由目標的剩余跳數。HttpTracker可以
在成功執行向路由目標的下一跳之后更新。HttpRouteDirector是一個幫助類,可以用來計算路由中的下一跳。這個類由HttpClient在
內部使用。</p><p style="color:inherit;font-family:inherit;font-size:inherit;font-style:inherit;">HttpRoutePlanner
是一個代表計算到基于執行上下文到給定目標完整路由策略的接口。HttpClient附帶兩個默認的HttpRoutePlanner實現。
ProxySelectorRoutePlanner是基于java.net.ProxySelector的。默認情況下,它會從系統屬性中或從運行應用
程序的瀏覽器中選取JVM的代理設置。DefaultHttpRoutePlanner實現既不使用任何Java系統屬性,也不使用系統或瀏覽器的代理設
置。它只基于HTTP如下面描述的參數計算路由。</p><h4>2.3.2 安全HTTP連接</h4><p style="color:inherit;font-family:inherit;font-size:inherit;font-style:inherit;">如果信息在兩個不能由非認證的第三方進行讀取或修改的終端之間傳輸,HTTP連接可以被認為是安全的。SSL/TLS協議是用來保證HTTP傳輸安全使用最廣泛的技術。而其它加密技術也可以被使用。通常來說,HTTP傳輸是在SSL/TLS加密連接之上分層的。</p><h3>2.4 HTTP路由參數</h3><div style="color:inherit;font-family:inherit;font-size:inherit;font-style:inherit;">這些參數可以影響路由計算:</div><ul><li>'http.route.default-proxy':定義可以被不使用JRE設置的默認路由規劃者使用的代理主機。這個參數期望得到一個HttpHost類型的值。如果這個參數沒有被設置,那么就會嘗試直接連接到目標。</li><li>'http.route.local-
address':定義一個本地地址由所有默認路由規劃者來使用。有多個網絡接口的機器中,這個參數可以被用于從連接源中選擇網絡接口。這個參數期望得到
一個java.net.InetAddress類型的值。如果這個參數沒有被設置,將會自動使用本地地址。</li><li>'http.route.forced-
route':定義一個由所有默認路由規劃者使用的強制路由。代替了計算路由,給定的強制路由將會被返回,盡管它指向一個完全不同的目標主機。這個參數期
望得到一個HttpRoute類型的值。如果這個參數沒有被設置,那么就使用默認的規則建立連接到目標服務器。</li></ul><h3>2.5 套接字工廠</h3><p style="color:inherit;font-family:inherit;font-size:inherit;font-style:inherit;">LayeredSocketFactory
是SocketFactory接口的擴展。分層的套接字工廠可HTTP連接內部使用java.net.Socket對象來處理數據在線路上的傳輸。它們依
賴SocketFactory接口來創建,初始化和連接套接字。這會使得HttpClient的用戶可以提供在運行時指定套接字初始化代碼的應用程序。
PlainSocketFactory是創建和初始化普通的(不加密的)套接字的默認工廠。</p><p style="color:inherit;font-family:inherit;font-size:inherit;font-style:inherit;">創建套接字的過程和連接到主機的過程是不成對的,所以套接字在連接操作封鎖時可以被關閉。</p><blockquote style="background-color:#F9F9FF;"><div style="color:inherit;font-family:inherit;font-size:inherit;font-style:inherit;">PlainSocketFactory sf = PlainSocketFactory.getSocketFactory();</div><div style="color:inherit;font-family:inherit;font-size:inherit;font-style:inherit;">Socket socket = sf.createSocket();</div><div style="color:inherit;font-family:inherit;font-size:inherit;font-style:inherit;">HttpParams params = new BasicHttpParams();</div><div style="color:inherit;font-family:inherit;font-size:inherit;font-style:inherit;">params.setParameter(CoreConnectionPNames.CONNECTION_TIMEOUT, 1000L);</div><div style="color:inherit;font-family:inherit;font-size:inherit;font-style:inherit;">sf.connectSocket(socket, "locahost", 8080, null, -1, params);</div></blockquote><h4>2.5.1 安全套接字分層</h4><p style="color:inherit;font-family:inherit;font-size:inherit;font-style:inherit;">LayeredSocketFactory
是SocketFactory接口的擴展。分層的套接字工廠可以創建在已經存在的普通套接字之上的分層套接字。套接字分層主要通過代理來創建安全的套接
字。HttpClient附帶實現了SSL/TLS分層的SSLSocketFactory。請注意HttpClient不使用任何自定義加密功能。它完
全依賴于標準的Java密碼學(JCE)和安全套接字(JSEE)擴展。</p><h4>2.5.2 SSL/TLS的定制</h4><p style="color:inherit;font-family:inherit;font-size:inherit;font-style:inherit;">HttpClient使用SSLSocketFactory來創建SSL連接。SSLSocketFactory允許高度定制。它可以使用javax.net.ssl.SSLContext的實例作為參數,并使用它來創建定制SSL連接。</p><blockquote style="background-color:#F9F9FF;"><div style="color:inherit;font-family:inherit;font-size:inherit;font-style:inherit;">TrustManager easyTrustManager = new X509TrustManager() {</div><div style="color:inherit;font-family:inherit;font-size:inherit;font-style:inherit;">@Override</div><div style="color:inherit;font-family:inherit;font-size:inherit;font-style:inherit;">public void checkClientTrusted(X509Certificate[] chain,</div><div style="color:inherit;font-family:inherit;font-size:inherit;font-style:inherit;">String authType) throws CertificateException {</div><div style="color:inherit;font-family:inherit;font-size:inherit;font-style:inherit;">// 哦,這很簡單!</div><div style="color:inherit;font-family:inherit;font-size:inherit;font-style:inherit;">}</div><div style="color:inherit;font-family:inherit;font-size:inherit;font-style:inherit;">@Override</div><div style="color:inherit;font-family:inherit;font-size:inherit;font-style:inherit;">public void checkServerTrusted(X509Certificate[] chain,</div><div style="color:inherit;font-family:inherit;font-size:inherit;font-style:inherit;">String authType) throws CertificateException {</div><div style="color:inherit;font-family:inherit;font-size:inherit;font-style:inherit;">//哦,這很簡單!</div><div style="color:inherit;font-family:inherit;font-size:inherit;font-style:inherit;">}</div><div style="color:inherit;font-family:inherit;font-size:inherit;font-style:inherit;">@Override</div><div style="color:inherit;font-family:inherit;font-size:inherit;font-style:inherit;">public X509Certificate[] getAcceptedIssuers() {</div><div style="color:inherit;font-family:inherit;font-size:inherit;font-style:inherit;">return null;</div><div style="color:inherit;font-family:inherit;font-size:inherit;font-style:inherit;">}</div><div style="color:inherit;font-family:inherit;font-size:inherit;font-style:inherit;">};</div><div style="color:inherit;font-family:inherit;font-size:inherit;font-style:inherit;">SSLContext sslcontext = SSLContext.getInstance("TLS");</div><div style="color:inherit;font-family:inherit;font-size:inherit;font-style:inherit;">sslcontext.init(null, new TrustManager[] { easyTrustManager }, null);</div><div style="color:inherit;font-family:inherit;font-size:inherit;font-style:inherit;">SSLSocketFactory sf = new SSLSocketFactory(sslcontext);</div><div style="color:inherit;font-family:inherit;font-size:inherit;font-style:inherit;">SSLSocket socket = (SSLSocket) sf.createSocket();</div><div style="color:inherit;font-family:inherit;font-size:inherit;font-style:inherit;">socket.setEnabledCipherSuites(new String[] { "SSL_RSA_WITH_RC4_128_MD5" });</div><div style="color:inherit;font-family:inherit;font-size:inherit;font-style:inherit;">HttpParams params = new BasicHttpParams();</div><div style="color:inherit;font-family:inherit;font-size:inherit;font-style:inherit;">params.setParameter(CoreConnectionPNames.CONNECTION_TIMEOUT, 1000L);</div><div style="color:inherit;font-family:inherit;font-size:inherit;font-style:inherit;">sf.connectSocket(socket, "locahost", 443, null, -1, params);</div></blockquote><div style="color:inherit;font-family:inherit;font-size:inherit;font-style:inherit;">SSLSocketFactory的定制暗示出一定程度SSL/TLS協議概念的熟悉,這個詳細的解釋超出了本文檔的范圍。請參考Java的安全套接字擴展[http://java.sun.com/j2se/1.5.0/docs/guide/</div><div style="color:inherit;font-family:inherit;font-size:inherit;font-style:inherit;">security/jsse/JSSERefGuide.html],這是javax.net.ssl.SSLContext和相關工具的詳細描述。</div><h4>2.5.3 主機名驗證</h4><div style="color:inherit;font-family:inherit;font-size:inherit;font-style:inherit;">除
了信任驗證和客戶端認證在SSL/TLS協議級上進行,一旦連接建立之后,HttpClient能可選地驗證目標主機名匹配存儲在服務器的X.509認證
中的名字。這個認證可以提供額外的服務器信任材料的真實保證。X509主機名驗證接口代表了主機名驗證的策略。HttpClient附帶了3個X509主
機名驗證器。很重要的一點是:主機名驗證不應該混淆SSL信任驗證。</div><ul><li>StrictHostnameVerifier:
嚴格的主機名驗證在Sun Java 1.4,Sun Java 5和Sun Java 6中是相同的。而且也非常接近IE6。這個實現似乎是兼容RFC
2818處理通配符的。主機名必須匹配第一個CN或任意的subject-alt。在CN和其它任意的subject-alt中可能會出現通配符。</li><li>BrowserCompatHostnameVerifier:
主機名驗證器和Curl和Firefox的工作方式是相同的。主機名必須匹配第一個CN或任意的subject-alt。在CN和其它任意的
subject-alt中可能會出現通配符。BrowserCompatHostnameVerifier和
StrictHostnameVerifier的唯一不同是使用BrowserCompatHostnameVerifier匹配所有子域的通配符(比
如”*.foo.com”),包括”a.b.foo.com”。</li><li>AllowAllHostnameVerifier:這個主機名驗證器基本上是關閉主機名驗證的。這個實現是一個空操作,而且不會拋出javax.net.ssl.SSLException異常。</li></ul><p style="color:inherit;font-family:inherit;font-size:inherit;font-style:inherit;">每一個默認的HttpClient使用BrowserCompatHostnameVerifier的實現。如果需要的話,它可以指定不同的主機名驗證器實現。</p><blockquote style="background-color:#F9F9FF;"><div style="color:inherit;font-family:inherit;font-size:inherit;font-style:inherit;">SSLSocketFactory sf = new SSLSocketFactory(SSLContext.getInstance("TLS"));</div><div style="color:inherit;font-family:inherit;font-size:inherit;font-style:inherit;">sf.setHostnameVerifier(SSLSocketFactory.STRICT_HOSTNAME_VERIFIER);</div></blockquote><h3>2.6 協議模式</h3><p style="color:inherit;font-family:inherit;font-size:inherit;font-style:inherit;">Scheme
類代表了一個協議模式,比如“http”或“https”同時包含一些協議屬性,比如默認端口,用來為給定協議創建java.net.Socket實例的
套接字工廠。SchemeRegistry類用來維持一組Scheme,當去通過請求URI建立連接時,HttpClient可以從中選擇:</p><blockquote style="background-color:#F9F9FF;"><div style="color:inherit;font-family:inherit;font-size:inherit;font-style:inherit;">Scheme http = new Scheme("http", PlainSocketFactory.getSocketFactory(), 80);</div><div style="color:inherit;font-family:inherit;font-size:inherit;font-style:inherit;">SSLSocketFactory sf = new SSLSocketFactory(SSLContext.getInstance("TLS"));</div><div style="color:inherit;font-family:inherit;font-size:inherit;font-style:inherit;">sf.setHostnameVerifier(SSLSocketFactory.STRICT_HOSTNAME_VERIFIER);</div><div style="color:inherit;font-family:inherit;font-size:inherit;font-style:inherit;">Scheme https = new Scheme("https", sf, 443);</div><div style="color:inherit;font-family:inherit;font-size:inherit;font-style:inherit;">SchemeRegistry sr = new SchemeRegistry();</div><div style="color:inherit;font-family:inherit;font-size:inherit;font-style:inherit;">sr.register(http);</div><div style="color:inherit;font-family:inherit;font-size:inherit;font-style:inherit;">sr.register(https);</div></blockquote><h3>2.7 HttpClient代理配置</h3><p style="color:inherit;font-family:inherit;font-size:inherit;font-style:inherit;">盡管HttpClient了解復雜的路由模式和代理鏈,它僅支持簡單直接的或開箱的跳式代理連接。</p><p style="color:inherit;font-family:inherit;font-size:inherit;font-style:inherit;">告訴HttpClient通過代理去連接到目標主機的最簡單方式是通過設置默認的代理參數:</p><blockquote style="background-color:#F9F9FF;"><div style="color:inherit;font-family:inherit;font-size:inherit;font-style:inherit;">DefaultHttpClient httpclient = new DefaultHttpClient();</div><div style="color:inherit;font-family:inherit;font-size:inherit;font-style:inherit;">HttpHost proxy = new HttpHost("someproxy", 8080);</div><div style="color:inherit;font-family:inherit;font-size:inherit;font-style:inherit;">httpclient.getParams().setParameter(ConnRoutePNames.DEFAULT_PROXY, proxy);</div></blockquote><p style="color:inherit;font-family:inherit;font-size:inherit;font-style:inherit;">也可以構建HttpClient使用標準的JRE代理選擇器來獲得代理信息:</p><blockquote style="background-color:#F9F9FF;"><div style="color:inherit;font-family:inherit;font-size:inherit;font-style:inherit;">DefaultHttpClient httpclient = new DefaultHttpClient();</div><div style="color:inherit;font-family:inherit;font-size:inherit;font-style:inherit;">ProxySelectorRoutePlanner routePlanner = new ProxySelectorRoutePlanner(</div><div style="color:inherit;font-family:inherit;font-size:inherit;font-style:inherit;">httpclient.getConnectionManager().getSchemeRegistry(),</div><div style="color:inherit;font-family:inherit;font-size:inherit;font-style:inherit;">ProxySelector.getDefault());</div><div style="color:inherit;font-family:inherit;font-size:inherit;font-style:inherit;">httpclient.setRoutePlanner(routePlanner);</div></blockquote><p style="color:inherit;font-family:inherit;font-size:inherit;font-style:inherit;">另外一種選擇,可以提供一個定制的RoutePlanner實現來獲得HTTP路由計算處理上的復雜的控制:</p><blockquote style="background-color:#F9F9FF;"><div style="color:inherit;font-family:inherit;font-size:inherit;font-style:inherit;">DefaultHttpClient httpclient = new DefaultHttpClient();</div><div style="color:inherit;font-family:inherit;font-size:inherit;font-style:inherit;">httpclient.setRoutePlanner(new HttpRoutePlanner() {</div><div style="color:inherit;font-family:inherit;font-size:inherit;font-style:inherit;">public HttpRoute determineRoute(HttpHost target,</div><div style="color:inherit;font-family:inherit;font-size:inherit;font-style:inherit;">HttpRequest request,</div><div style="color:inherit;font-family:inherit;font-size:inherit;font-style:inherit;">HttpContext context) throws HttpException {</div><div style="color:inherit;font-family:inherit;font-size:inherit;font-style:inherit;">return new HttpRoute(target, null, new HttpHost("someproxy", 8080),</div><div style="color:inherit;font-family:inherit;font-size:inherit;font-style:inherit;">"https".equalsIgnoreCase(target.getSchemeName()));</div><div style="color:inherit;font-family:inherit;font-size:inherit;font-style:inherit;">}</div><div style="color:inherit;font-family:inherit;font-size:inherit;font-style:inherit;">});</div></blockquote><h3>2.8 HTTP連接管理器</h3><h4>2.8.1 連接操作器</h4><p style="color:inherit;font-family:inherit;font-size:inherit;font-style:inherit;">連
接操作是客戶端的低層套接字或可以通過外部實體,通常稱為連接操作的被操作的狀態的連接。OperatedClientConnection接口擴展了
HttpClientConnection接口而且定義了額外的控制連接套接字的方法。ClientConnectionOperator接口代表了創建
實例和更新那些對象低層套接字的策略。實現類最有可能利用SocketFactory來創建java.net.Socket實例。
ClientConnectionOperator接口可以讓HttpClient的用戶提供一個連接操作的定制策略和提供可選實現
OperatedClientConnection接口的能力。</p><h4>2.8.2 管理連接和連接管理器</h4><p style="color:inherit;font-family:inherit;font-size:inherit;font-style:inherit;">HTTP
連接是復雜的,有狀態的,線程不安全的對象需要正確的管理以便正確地執行功能。HTTP連接在同一時間僅僅只能由一個執行線程來使用。
HttpClient采用一個特殊實體來管理訪問HTTP連接,這被稱為HTTP連接管理器,代表了ClientConnectionManager接
口。一個HTTP連接管理器的目的是作為工廠服務于新的HTTP連接,管理持久連接和同步訪問持久連接來確保同一時間僅有一個線程可以訪問一個連接。</p><p style="color:inherit;font-family:inherit;font-size:inherit;font-style:inherit;">內
部的HTTP連接管理器和OperatedClientConnection實例一起工作,但是它們為服務消耗器
ManagedClientConnection提供實例。ManagedClientConnection扮演連接之上管理狀態控制所有I/O操作的
OperatedClientConnection實例的包裝器。它也抽象套接字操作,提供打開和更新去創建路由套接字便利的方法。
ManagedClientConnection實例了解產生它們到連接管理器的鏈接,而且基于這個事實,當不再被使用時,它們必須返回到管理器。
ManagedClientConnection類也實現了ConnectionReleaseTrigger接口,可以被用來觸發釋放連接返回給管理
器。一旦釋放連接操作被觸發了,被包裝的連接從ManagedClientConnection包裝器中脫
離,OperatedClientConnection實例被返回給管理器。盡管服務消耗器仍然持有ManagedClientConnection實例
的引用,它也不再去執行任何I/O操作或有意無意地改變的OperatedClientConnection狀態。</p><p style="color:inherit;font-family:inherit;font-size:inherit;font-style:inherit;">這里有一個從連接管理器中獲取連接的示例:</p><blockquote style="background-color:#F9F9FF;"><div style="color:inherit;font-family:inherit;font-size:inherit;font-style:inherit;">HttpParams params = new BasicHttpParams();</div><div style="color:inherit;font-family:inherit;font-size:inherit;font-style:inherit;">Scheme http = new Scheme("http", PlainSocketFactory.getSocketFactory(), 80);</div><div style="color:inherit;font-family:inherit;font-size:inherit;font-style:inherit;">SchemeRegistry sr = new SchemeRegistry();</div><div style="color:inherit;font-family:inherit;font-size:inherit;font-style:inherit;">sr.register(http);</div><div style="color:inherit;font-family:inherit;font-size:inherit;font-style:inherit;">ClientConnectionManager connMrg = new SingleClientConnManager(params, sr);</div><div style="color:inherit;font-family:inherit;font-size:inherit;font-style:inherit;">// 請求新連接。這可能是一個很長的過程。</div><div style="color:inherit;font-family:inherit;font-size:inherit;font-style:inherit;">ClientConnectionRequest connRequest = connMrg.requestConnection(</div><div style="color:inherit;font-family:inherit;font-size:inherit;font-style:inherit;">new HttpRoute(new HttpHost("localhost", 80)), null);</div><div style="color:inherit;font-family:inherit;font-size:inherit;font-style:inherit;">// 等待連接10秒</div><div style="color:inherit;font-family:inherit;font-size:inherit;font-style:inherit;">ManagedClientConnection conn = connRequest.getConnection(10, TimeUnit.SECONDS);</div><div style="color:inherit;font-family:inherit;font-size:inherit;font-style:inherit;">try {</div><div style="color:inherit;font-family:inherit;font-size:inherit;font-style:inherit;">// 用連接在做有用的事情。當完成時釋放連接。</div><div style="color:inherit;font-family:inherit;font-size:inherit;font-style:inherit;">conn.releaseConnection();</div><div style="color:inherit;font-family:inherit;font-size:inherit;font-style:inherit;">} catch (IOException ex) {</div><div style="color:inherit;font-family:inherit;font-size:inherit;font-style:inherit;">// 在I/O error之上終止連接。</div><div style="color:inherit;font-family:inherit;font-size:inherit;font-style:inherit;">conn.abortConnection();</div><div style="color:inherit;font-family:inherit;font-size:inherit;font-style:inherit;">throw ex;</div><div style="color:inherit;font-family:inherit;font-size:inherit;font-style:inherit;">}</div></blockquote><p style="color:inherit;font-family:inherit;font-size:inherit;font-style:inherit;">如果需要,連接請求可以通過調用來ClientConnectionRequest#abortRequest()方法過早地中斷。這會解鎖在ClientConnectionRequest#getConnection()方法中被阻止的線程。</p><p style="color:inherit;font-family:inherit;font-size:inherit;font-style:inherit;">一旦響應內容被完全消耗后,BasicManagedEntity包裝器類可以用來保證自動釋放低層的連接。HttpClient內部使用這個機制來實現透明地對所有從HttpClient#execute()方法中獲得響應釋放連接:</p><blockquote style="background-color:#F9F9FF;"><div style="color:inherit;font-family:inherit;font-size:inherit;font-style:inherit;">ClientConnectionRequest connRequest = connMrg.requestConnection(</div><div style="color:inherit;font-family:inherit;font-size:inherit;font-style:inherit;">new HttpRoute(new HttpHost("localhost", 80)), null);</div><div style="color:inherit;font-family:inherit;font-size:inherit;font-style:inherit;">ManagedClientConnection conn = connRequest.getConnection(10, TimeUnit.SECONDS);</div><div style="color:inherit;font-family:inherit;font-size:inherit;font-style:inherit;">try {</div><div style="color:inherit;font-family:inherit;font-size:inherit;font-style:inherit;">BasicHttpRequest request = new BasicHttpRequest("GET", "/");</div><div style="color:inherit;font-family:inherit;font-size:inherit;font-style:inherit;">conn.sendRequestHeader(request);</div><div style="color:inherit;font-family:inherit;font-size:inherit;font-style:inherit;">HttpResponse response = conn.receiveResponseHeader();</div><div style="color:inherit;font-family:inherit;font-size:inherit;font-style:inherit;">conn.receiveResponseEntity(response);</div><div style="color:inherit;font-family:inherit;font-size:inherit;font-style:inherit;">HttpEntity entity = response.getEntity();</div><div style="color:inherit;font-family:inherit;font-size:inherit;font-style:inherit;">if (entity != null) {</div><div style="color:inherit;font-family:inherit;font-size:inherit;font-style:inherit;">BasicManagedEntity managedEntity = new BasicManagedEntity(entity, conn, true);</div><div style="color:inherit;font-family:inherit;font-size:inherit;font-style:inherit;">// 替換實體</div><div style="color:inherit;font-family:inherit;font-size:inherit;font-style:inherit;">response.setEntity(managedEntity);</div><div style="color:inherit;font-family:inherit;font-size:inherit;font-style:inherit;">}</div><div style="color:inherit;font-family:inherit;font-size:inherit;font-style:inherit;">// 使用響應對象做有用的事情。當響應內容被消耗后這個連接將會自動釋放。</div><div style="color:inherit;font-family:inherit;font-size:inherit;font-style:inherit;">} catch (IOException ex) {</div><div style="color:inherit;font-family:inherit;font-size:inherit;font-style:inherit;">//在I/O error之上終止連接。</div><div style="color:inherit;font-family:inherit;font-size:inherit;font-style:inherit;">conn.abortConnection();</div><div style="color:inherit;font-family:inherit;font-size:inherit;font-style:inherit;">throw ex;</div><div style="color:inherit;font-family:inherit;font-size:inherit;font-style:inherit;">}</div></blockquote><h4>2.8.3 簡單連接管理器</h4><p style="color:inherit;font-family:inherit;font-size:inherit;font-style:inherit;">SingleClientConnManager
是一個簡單的連接管理器,在同一時間它僅僅維護一個連接。盡管這個類是線程安全的,但它應該被用于一個執行線程。
SingleClientConnManager對于同一路由的后續請求會盡量重用連接。而如果持久連接的路由不匹配連接請求的話,它也會關閉存在的連接
之后對給定路由再打開一個新的。如果連接已經被分配,將會拋出java.lang.IllegalStateException異常。</p><p style="color:inherit;font-family:inherit;font-size:inherit;font-style:inherit;">對于每個默認連接,HttpClient使用SingleClientConnManager。</p><h4>2.8.4 連接池管理器</h4><p style="color:inherit;font-family:inherit;font-size:inherit;font-style:inherit;">ThreadSafeClientConnManager
是一個復雜的實現來管理客戶端連接池,它也可以從多個執行線程中服務連接請求。對每個基本的路由,連接都是池管理的。對于路由的請求,管理器在池中有可用
的持久性連接,將被從池中租賃連接服務,而不是創建一個新的連接。</p><p style="color:inherit;font-family:inherit;font-size:inherit;font-style:inherit;">ThreadSafeClientConnManager
維護每個基本路由的最大連接限制。每個默認的實現對每個給定路由將會創建不超過兩個的并發連接,而總共也不會超過20個連接。對于很多真實的應用程序,這
個限制也證明很大的制約,特別是他們在服務中使用HTTP作為傳輸協議。連接限制,也可以使用HTTP參數來進行調整。</p><p style="color:inherit;font-family:inherit;font-size:inherit;font-style:inherit;">這個示例展示了連接池參數是如何來調整的:</p><blockquote style="background-color:#F9F9FF;"><div style="color:inherit;font-family:inherit;font-size:inherit;font-style:inherit;">HttpParams params = new BasicHttpParams();</div><div style="color:inherit;font-family:inherit;font-size:inherit;font-style:inherit;">// 增加最大連接到200</div><div style="color:inherit;font-family:inherit;font-size:inherit;font-style:inherit;">ConnManagerParams.setMaxTotalConnections(params, 200);</div><div style="color:inherit;font-family:inherit;font-size:inherit;font-style:inherit;">// 增加每個路由的默認最大連接到20</div><div style="color:inherit;font-family:inherit;font-size:inherit;font-style:inherit;">ConnPerRouteBean connPerRoute = new ConnPerRouteBean(20);</div><div style="color:inherit;font-family:inherit;font-size:inherit;font-style:inherit;">// 對localhost:80增加最大連接到50</div><div style="color:inherit;font-family:inherit;font-size:inherit;font-style:inherit;">HttpHost localhost = new HttpHost("locahost", 80);</div><div style="color:inherit;font-family:inherit;font-size:inherit;font-style:inherit;">connPerRoute.setMaxForRoute(new HttpRoute(localhost), 50);</div><div style="color:inherit;font-family:inherit;font-size:inherit;font-style:inherit;">ConnManagerParams.setMaxConnectionsPerRoute(params, connPerRoute);</div><div style="color:inherit;font-family:inherit;font-size:inherit;font-style:inherit;">SchemeRegistry schemeRegistry = new SchemeRegistry();</div><div style="color:inherit;font-family:inherit;font-size:inherit;font-style:inherit;">schemeRegistry.register(</div><div style="color:inherit;font-family:inherit;font-size:inherit;font-style:inherit;">new Scheme("http", PlainSocketFactory.getSocketFactory(), 80));</div><div style="color:inherit;font-family:inherit;font-size:inherit;font-style:inherit;">schemeRegistry.register(</div><div style="color:inherit;font-family:inherit;font-size:inherit;font-style:inherit;">new Scheme("https", SSLSocketFactory.getSocketFactory(), 443));</div><div style="color:inherit;font-family:inherit;font-size:inherit;font-style:inherit;">ClientConnectionManager cm = new ThreadSafeClientConnManager(params, schemeRegistry);</div><div style="color:inherit;font-family:inherit;font-size:inherit;font-style:inherit;">HttpClient httpClient = new DefaultHttpClient(cm, params);</div></blockquote><h4>2.8.5 連接管理器關閉</h4><p style="color:inherit;font-family:inherit;font-size:inherit;font-style:inherit;">當一個HttpClient實例不再需要時,而且即將走出使用范圍,那么關閉連接管理器來保證由管理器保持活動的所有連接被關閉,由連接分配的系統資源被釋放是很重要的。</p><blockquote style="background-color:#F9F9FF;"><div style="color:inherit;font-family:inherit;font-size:inherit;font-style:inherit;">DefaultHttpClient httpclient = new DefaultHttpClient();</div><div style="color:inherit;font-family:inherit;font-size:inherit;font-style:inherit;">HttpGet httpget = new HttpGet("http://www.google.com/");</div><div style="color:inherit;font-family:inherit;font-size:inherit;font-style:inherit;">HttpResponse response = httpclient.execute(httpget);</div><div style="color:inherit;font-family:inherit;font-size:inherit;font-style:inherit;">HttpEntity entity = response.getEntity();</div><div style="color:inherit;font-family:inherit;font-size:inherit;font-style:inherit;">System.out.println(response.getStatusLine());</div><div style="color:inherit;font-family:inherit;font-size:inherit;font-style:inherit;">if (entity != null) {</div><div style="color:inherit;font-family:inherit;font-size:inherit;font-style:inherit;">entity.consumeContent();</div><div style="color:inherit;font-family:inherit;font-size:inherit;font-style:inherit;">}</div><div style="color:inherit;font-family:inherit;font-size:inherit;font-style:inherit;">httpclient.getConnectionManager().shutdown();</div></blockquote><h3>2.9 連接管理參數</h3><div style="color:inherit;font-family:inherit;font-size:inherit;font-style:inherit;">這些是可以用于定制標準HTTP連接管理器實現的參數:</div><ul><li>'http.conn-
manager.timeout':定義了當從ClientConnectionManager中檢索ManagedClientConnection實
例時使用的毫秒級的超時時間。這個參數期望得到一個java.lang.Long類型的值。如果這個參數沒有被設置,連接請求就不會超時(無限大的超時時
間)。</li><li>'http.conn-manager.max-per-route':定義了每個路由連接的最大數量。這個限制由客戶端連接管理器來解釋,而且應用于獨立的管理器實例。這個參數期望得到一個ConnPerRoute類型的值。</li><li>'http.conn-manager.max-total':定義了總共連接的最大數目。這個限制由客戶端連接管理器來解釋,而且應用于獨立的管理器實例。這個參數期望得到一個java.lang.Integer類型的值。</li></ul><h3>2.10 多線程執行請求</h3><p style="color:inherit;font-family:inherit;font-size:inherit;font-style:inherit;">當配備連接池管理器時,比如ThreadSafeClientConnManager,HttpClient可以同時被用來執行多個請求,使用多線程執行。</p><p style="color:inherit;font-family:inherit;font-size:inherit;font-style:inherit;">ThreadSafeClientConnManager
將會分配基于它的配置的連接。如果對于給定路由的所有連接都被租出了,那么連接的請求將會阻塞,直到一個連接被釋放回連接池。它可以通過設置
'http.conn-manager.timeout'為一個正數來保證連接管理器不會在連接請求執行時無限期的被阻塞。如果連接請求不能在給定的時間
周期內被響應,將會拋出ConnectionPoolTimeoutException異常。</p><blockquote style="background-color:#F9F9FF;"><div style="color:inherit;font-family:inherit;font-size:inherit;font-style:inherit;">HttpParams params = new BasicHttpParams();</div><div style="color:inherit;font-family:inherit;font-size:inherit;font-style:inherit;">SchemeRegistry schemeRegistry = new SchemeRegistry();</div><div style="color:inherit;font-family:inherit;font-size:inherit;font-style:inherit;">schemeRegistry.register(</div><div style="color:inherit;font-family:inherit;font-size:inherit;font-style:inherit;">new Scheme("http", PlainSocketFactory.getSocketFactory(), 80));</div><div style="color:inherit;font-family:inherit;font-size:inherit;font-style:inherit;">ClientConnectionManager cm = new ThreadSafeClientConnManager(params, schemeRegistry);</div><div style="color:inherit;font-family:inherit;font-size:inherit;font-style:inherit;">HttpClient httpClient = new DefaultHttpClient(cm, params);</div><div style="color:inherit;font-family:inherit;font-size:inherit;font-style:inherit;">// 執行GET方法的URI</div><div style="color:inherit;font-family:inherit;font-size:inherit;font-style:inherit;">String[] urisToGet = {</div><div style="color:inherit;font-family:inherit;font-size:inherit;font-style:inherit;">"http://www.domain1.com/",</div><div style="color:inherit;font-family:inherit;font-size:inherit;font-style:inherit;">"http://www.domain2.com/",</div><div style="color:inherit;font-family:inherit;font-size:inherit;font-style:inherit;">"http://www.domain3.com/",</div><div style="color:inherit;font-family:inherit;font-size:inherit;font-style:inherit;">"http://www.domain4.com/"</div><div style="color:inherit;font-family:inherit;font-size:inherit;font-style:inherit;">};</div><div style="color:inherit;font-family:inherit;font-size:inherit;font-style:inherit;">// 為每個URI創建一個線程</div><div style="color:inherit;font-family:inherit;font-size:inherit;font-style:inherit;">GetThread[] threads = new GetThread[urisToGet.length];</div><div style="color:inherit;font-family:inherit;font-size:inherit;font-style:inherit;">for (int i = 0; i < threads.length; i++) {</div><div style="color:inherit;font-family:inherit;font-size:inherit;font-style:inherit;">HttpGet httpget = new HttpGet(urisToGet[i]);</div><div style="color:inherit;font-family:inherit;font-size:inherit;font-style:inherit;">threads[i] = new GetThread(httpClient, httpget);</div><div style="color:inherit;font-family:inherit;font-size:inherit;font-style:inherit;">}</div></blockquote><div style="color:inherit;font-family:inherit;font-size:inherit;font-style:inherit;"><blockquote style="background-color:#F9F9FF;"><div style="color:inherit;font-family:inherit;font-size:inherit;font-style:inherit;">// 開始執行線程</div><div style="color:inherit;font-family:inherit;font-size:inherit;font-style:inherit;">for (int j = 0; j < threads.length; j++) {</div><div style="color:inherit;font-family:inherit;font-size:inherit;font-style:inherit;">threads[j].start();</div><div style="color:inherit;font-family:inherit;font-size:inherit;font-style:inherit;">}</div><div style="color:inherit;font-family:inherit;font-size:inherit;font-style:inherit;">// 合并線程</div><div style="color:inherit;font-family:inherit;font-size:inherit;font-style:inherit;">for (int j = 0; j < threads.length; j++) {</div><div style="color:inherit;font-family:inherit;font-size:inherit;font-style:inherit;">threads[j].join();</div><div style="color:inherit;font-family:inherit;font-size:inherit;font-style:inherit;">}</div><div style="color:inherit;font-family:inherit;font-size:inherit;font-style:inherit;"> </div><div style="color:inherit;font-family:inherit;font-size:inherit;font-style:inherit;"><div style="color:inherit;font-family:inherit;font-size:inherit;font-style:inherit;">static class GetThread extends Thread {</div><div style="color:inherit;font-family:inherit;font-size:inherit;font-style:inherit;">private final HttpClient httpClient;</div><div style="color:inherit;font-family:inherit;font-size:inherit;font-style:inherit;">private final HttpContext context;</div><div style="color:inherit;font-family:inherit;font-size:inherit;font-style:inherit;">private final HttpGet httpget;</div><div style="color:inherit;font-family:inherit;font-size:inherit;font-style:inherit;">public GetThread(HttpClient httpClient, HttpGet httpget) {</div><div style="color:inherit;font-family:inherit;font-size:inherit;font-style:inherit;">this.httpClient = httpClient;</div><div style="color:inherit;font-family:inherit;font-size:inherit;font-style:inherit;">this.context = new BasicHttpContext();</div><div style="color:inherit;font-family:inherit;font-size:inherit;font-style:inherit;">this.httpget = httpget;</div><div style="color:inherit;font-family:inherit;font-size:inherit;font-style:inherit;">}</div><div style="color:inherit;font-family:inherit;font-size:inherit;font-style:inherit;">@Override</div><div style="color:inherit;font-family:inherit;font-size:inherit;font-style:inherit;">public void run() {</div><div style="color:inherit;font-family:inherit;font-size:inherit;font-style:inherit;">try {</div><div style="color:inherit;font-family:inherit;font-size:inherit;font-style:inherit;">HttpResponse response = this.httpClient.execute(this.httpget, this.context);</div><div style="color:inherit;font-family:inherit;font-size:inherit;font-style:inherit;">HttpEntity entity = response.getEntity();</div><div style="color:inherit;font-family:inherit;font-size:inherit;font-style:inherit;">if (entity != null) {</div><div style="color:inherit;font-family:inherit;font-size:inherit;font-style:inherit;">// 對實體做些有用的事情...</div><div style="color:inherit;font-family:inherit;font-size:inherit;font-style:inherit;">// 保證連接能釋放回管理器</div><div style="color:inherit;font-family:inherit;font-size:inherit;font-style:inherit;">entity.consumeContent();</div><div style="color:inherit;font-family:inherit;font-size:inherit;font-style:inherit;">}</div><div style="color:inherit;font-family:inherit;font-size:inherit;font-style:inherit;">} catch (Exception ex) {</div><div style="color:inherit;font-family:inherit;font-size:inherit;font-style:inherit;">this.httpget.abort();</div><div style="color:inherit;font-family:inherit;font-size:inherit;font-style:inherit;">}</div><div style="color:inherit;font-family:inherit;font-size:inherit;font-style:inherit;">}</div><div style="color:inherit;font-family:inherit;font-size:inherit;font-style:inherit;">}</div></div></blockquote></div><h3>2.11 連接收回策略</h3><p style="color:inherit;font-family:inherit;font-size:inherit;font-style:inherit;">一
個經典的阻塞I/O模型的主要缺點是網絡套接字僅當I/O操作阻塞時才可以響應I/O事件。當一個連接被釋放返回管理器時,它可以被保持活動狀態而卻不能
監控套接字的狀態和響應任何I/O事件。如果連接在服務器端關閉,那么客戶端連接也不能去偵測連接狀態中的變化和關閉本端的套接字去作出適當響應。</p><p style="color:inherit;font-family:inherit;font-size:inherit;font-style:inherit;">HttpClient
通過測試連接是否是過時的來嘗試去減輕這個問題,這已經不再有效了,因為它已經在服務器端關閉了,之前使用執行HTTP請求的連接。過時的連接檢查也并不
是100%的穩定,反而對每次請求執行還要增加10到30毫秒的開銷。唯一可行的而不涉及到每個對空閑連接的套接字模型線程解決方案,是使用專用的監控線
程來收回因為長時間不活動而被認為是過期的連接。監控線程可以周期地調用
ClientConnectionManager#closeExpiredConnections()方法來關閉所有過期的連接,從連接池中收回關閉的
連接。它也可以選擇性調用ClientConnectionManager#closeIdleConnections()方法來關閉所有已經空閑超過給
定時間周期的連接。</p><blockquote style="background-color:#F9F9FF;"><div style="color:inherit;font-family:inherit;font-size:inherit;font-style:inherit;">public static class IdleConnectionMonitorThread extends Thread {</div><div style="color:inherit;font-family:inherit;font-size:inherit;font-style:inherit;">private final ClientConnectionManager connMgr;</div><div style="color:inherit;font-family:inherit;font-size:inherit;font-style:inherit;">private volatile boolean shutdown;</div><div style="color:inherit;font-family:inherit;font-size:inherit;font-style:inherit;">public IdleConnectionMonitorThread(ClientConnectionManager connMgr) {</div><div style="color:inherit;font-family:inherit;font-size:inherit;font-style:inherit;">super();</div><div style="color:inherit;font-family:inherit;font-size:inherit;font-style:inherit;">this.connMgr = connMgr;</div><div style="color:inherit;font-family:inherit;font-size:inherit;font-style:inherit;">}</div><div style="color:inherit;font-family:inherit;font-size:inherit;font-style:inherit;">@Override</div><div style="color:inherit;font-family:inherit;font-size:inherit;font-style:inherit;">public void run() {</div><div style="color:inherit;font-family:inherit;font-size:inherit;font-style:inherit;">try {</div><div style="color:inherit;font-family:inherit;font-size:inherit;font-style:inherit;">while (!shutdown) {</div><div style="color:inherit;font-family:inherit;font-size:inherit;font-style:inherit;">synchronized (this) {</div><div style="color:inherit;font-family:inherit;font-size:inherit;font-style:inherit;">wait(5000);</div><div style="color:inherit;font-family:inherit;font-size:inherit;font-style:inherit;">// 關閉過期連接</div><div style="color:inherit;font-family:inherit;font-size:inherit;font-style:inherit;">connMgr.closeExpiredConnections();</div><div style="color:inherit;font-family:inherit;font-size:inherit;font-style:inherit;">// 可選地,關閉空閑超過30秒的連接</div><div style="color:inherit;font-family:inherit;font-size:inherit;font-style:inherit;">connMgr.closeIdleConnections(30, TimeUnit.SECONDS);</div><div style="color:inherit;font-family:inherit;font-size:inherit;font-style:inherit;">}</div><div style="color:inherit;font-family:inherit;font-size:inherit;font-style:inherit;">}</div><div style="color:inherit;font-family:inherit;font-size:inherit;font-style:inherit;">} catch (InterruptedException ex) {</div><div style="color:inherit;font-family:inherit;font-size:inherit;font-style:inherit;">// 終止</div><div style="color:inherit;font-family:inherit;font-size:inherit;font-style:inherit;">}</div><div style="color:inherit;font-family:inherit;font-size:inherit;font-style:inherit;">}</div><div style="color:inherit;font-family:inherit;font-size:inherit;font-style:inherit;">public void shutdown() {</div><div style="color:inherit;font-family:inherit;font-size:inherit;font-style:inherit;">shutdown = true;</div><div style="color:inherit;font-family:inherit;font-size:inherit;font-style:inherit;">synchronized (this) {</div><div style="color:inherit;font-family:inherit;font-size:inherit;font-style:inherit;">notifyAll();</div><div style="color:inherit;font-family:inherit;font-size:inherit;font-style:inherit;">}</div><div style="color:inherit;font-family:inherit;font-size:inherit;font-style:inherit;">}</div><div style="color:inherit;font-family:inherit;font-size:inherit;font-style:inherit;">}</div></blockquote><h3>2.12 連接保持活動的策略</h3><p style="color:inherit;font-family:inherit;font-size:inherit;font-style:inherit;">HTTP
規范沒有確定一個持久連接可能或應該保持活動多長時間。一些HTTP服務器使用非標準的頭部信息Keep-Alive來告訴客戶端它們想在服務器端保持連
接活動的周期秒數。如果這個信息可用,HttClient就會利用這個它。如果頭部信息Keep-Alive在響應中不存在,HttpClient假設連
接無限期的保持活動。然而許多現實中的HTTP服務器配置了在特定不活動周期之后丟掉持久連接來保存系統資源,往往這是不通知客戶端的。如果默認的策略證
明是過于樂觀的,那么就會有人想提供一個定制的保持活動策略。</p><div style="color:inherit;font-family:inherit;font-size:inherit;font-style:inherit;">DefaultHttpClient httpclient = new DefaultHttpClient();</div><div style="color:inherit;font-family:inherit;font-size:inherit;font-style:inherit;">httpclient.setKeepAliveStrategy(new ConnectionKeepAliveStrategy() {</div><div style="color:inherit;font-family:inherit;font-size:inherit;font-style:inherit;">public long getKeepAliveDuration(HttpResponse response, HttpContext context) {</div><div style="color:inherit;font-family:inherit;font-size:inherit;font-style:inherit;">// 兌現'keep-alive'頭部信息</div><div style="color:inherit;font-family:inherit;font-size:inherit;font-style:inherit;">HeaderElementIterator it = new BasicHeaderElementIterator(</div><div style="color:inherit;font-family:inherit;font-size:inherit;font-style:inherit;">response.headerIterator(HTTP.CONN_KEEP_ALIVE));</div><div style="color:inherit;font-family:inherit;font-size:inherit;font-style:inherit;">while (it.hasNext()) {</div><div style="color:inherit;font-family:inherit;font-size:inherit;font-style:inherit;">HeaderElement he = it.nextElement();</div><div style="color:inherit;font-family:inherit;font-size:inherit;font-style:inherit;">String param = he.getName();</div><div style="color:inherit;font-family:inherit;font-size:inherit;font-style:inherit;">String value = he.getValue();</div><div style="color:inherit;font-family:inherit;font-size:inherit;font-style:inherit;">if (value != null && param.equalsIgnoreCase("timeout")) {</div><div style="color:inherit;font-family:inherit;font-size:inherit;font-style:inherit;">try {</div><div style="color:inherit;font-family:inherit;font-size:inherit;font-style:inherit;">return Long.parseLong(value) * 1000;</div><div style="color:inherit;font-family:inherit;font-size:inherit;font-style:inherit;">} catch(NumberFormatException ignore) {</div><div style="color:inherit;font-family:inherit;font-size:inherit;font-style:inherit;">}</div><div style="color:inherit;font-family:inherit;font-size:inherit;font-style:inherit;">}</div><div style="color:inherit;font-family:inherit;font-size:inherit;font-style:inherit;">}</div><div style="color:inherit;font-family:inherit;font-size:inherit;font-style:inherit;">HttpHost target = (HttpHost) context.getAttribute(</div><div style="color:inherit;font-family:inherit;font-size:inherit;font-style:inherit;">ExecutionContext.HTTP_TARGET_HOST);</div><div style="color:inherit;font-family:inherit;font-size:inherit;font-style:inherit;">if ("www.naughty-server.com".equalsIgnoreCase(target.getHostName())) {</div><div style="color:inherit;font-family:inherit;font-size:inherit;font-style:inherit;">// 只保持活動5秒</div><div style="color:inherit;font-family:inherit;font-size:inherit;font-style:inherit;">return 5 * 1000;</div><div style="color:inherit;font-family:inherit;font-size:inherit;font-style:inherit;">} else {</div><div style="color:inherit;font-family:inherit;font-size:inherit;font-style:inherit;">// 否則保持活動30秒</div><div style="color:inherit;font-family:inherit;font-size:inherit;font-style:inherit;">return 30 * 1000;</div><div style="color:inherit;font-family:inherit;font-size:inherit;font-style:inherit;">}</div><div style="color:inherit;font-family:inherit;font-size:inherit;font-style:inherit;">}</div><div style="color:inherit;font-family:inherit;font-size:inherit;font-style:inherit;">});</div></div></div>
- Introduction
- 爬蟲相關技能介紹
- 爬蟲簡單介紹
- 爬蟲涉及到的知識點
- 爬蟲用途
- 爬蟲流程介紹
- 需求描述
- Http請求處理
- http基礎知識介紹
- http狀態碼
- httpheader
- java原生態處理http
- URL類
- 獲取URL請求狀態
- 模擬Http請求
- apache httpclient
- Httpclient1
- httpclient2
- httpclient3
- httpclient4
- httpclient5
- httpclient6
- okhttp
- OKhttp使用教程
- 技術使用
- java執行javascript
- 網頁解析
- Xpath介紹
- HtmlCleaner
- HtmlCleaner介紹
- HtmlCleaner使用
- HtmlParser
- HtmlParser介紹
- Jsoup
- 解析和遍歷一個HTML文檔
- 解析一個HTML字符串
- 解析一個body片斷
- 從一個URL加載一個Document
- 從一個文件加載一個文檔
- 使用DOM方法來遍歷一個文檔
- 使用選擇器語法來查找元素
- 從元素抽取屬性,文本和HTML
- 處理URLs
- 示例程序 獲取所有鏈接
- 設置屬性的值
- 設置一個元素的HTML內容
- 消除不受信任的HTML (來防止XSS攻擊)
- 正則表達式
- elasticsearch筆記
- 下載安裝elasticsearch
- 檢查es服務健康