<rt id="bn8ez"></rt>
<label id="bn8ez"></label>

  • <span id="bn8ez"></span>

    <label id="bn8ez"><meter id="bn8ez"></meter></label>

    少年阿賓

    那些青春的歲月

      BlogJava :: 首頁 :: 聯系 :: 聚合  :: 管理
      500 Posts :: 0 Stories :: 135 Comments :: 0 Trackbacks

    #

    第五章 HTTP客戶端服務

    5.1 HttpClient門面

    HttpClient接口代表了最重要的HTTP請求執行的契約。它沒有在請求執行處理上強加限制或特殊細節,而在連接管理,狀態管理,認證和處理重定向到具體實現上留下了細節。這應該使得很容易使用額外的功能,比如響應內容緩存來裝飾接口。

    DefaultHttpClient是HttpClient接口的默認實現。這個類扮演了很多特殊用戶程序或策略接口實現負責處理特定HTTP協議方面,比如重定向到處理認證或做出關于連接持久化和保持活動的持續時間決定的門面。這使得用戶可以選擇使用定制,具體程序等來替換某些方面默認實現。

    DefaultHttpClient httpclient = new DefaultHttpClient();
    httpclient.setKeepAliveStrategy(new DefaultConnectionKeepAliveStrategy() {
    @Override
    public long getKeepAliveDuration(HttpResponse response,
    HttpContext context) {
    long keepAlive = super.getKeepAliveDuration(response, context);
    if (keepAlive == -1) {
    // 如果keep-alive值沒有由服務器明確設置,那么保持連接持續5秒。
    keepAlive = 5000;
    }
    return keepAlive;
    }
    });

    DefaultHttpClient也維護一組協議攔截器,意在處理即將離開的請求和即將到達的響應,而且提供管理那些攔截器的方法。新的協議攔截器可以被引入到協議處理器鏈中,或在需要時從中移除。內部的協議攔截器存儲在一個簡單的java.util.ArrayList中。它們以被加入到list中的自然順序來執行。

    DefaultHttpClient httpclient = new DefaultHttpClient();
    httpclient.removeRequestInterceptorByClass(RequestUserAgent.class);
    httpclient.addRequestInterceptor(new HttpRequestInterceptor() {
    public void process(
    HttpRequest request, HttpContext context)
    throws HttpException, IOException {
    request.setHeader(HTTP.USER_AGENT, "My-own-client");
    }
    });

    DefaultHttpClient是線程安全的。建議相同的這個類的實例被重用于多個請求的執行。當一個DefaultHttpClient實例不再需要而且要脫離范圍時,和它關聯的連接管理器必須調用ClientConnectionManager#shutdown()方法關閉。

    HttpClient httpclient = new DefaultHttpClient();
    // 做些有用的事
    httpclient.getConnectionManager().shutdown();

    5.2 HttpClient參數

    這些是可以用于定制默認HttpClient實現行為的參數:
    • 'http.protocol.handle-redirects':定義了重定向是否應該自動處理。這個參數期望得到一個java.lang.Boolean類型的值。如果這個參數沒有被設置,HttpClient將會自動處理重定向。
    • 'http.protocol.reject-relative-redirect':定義了是否相對的重定向應該被拒絕。HTTP規范需要位置值是一個絕對URI。這個參數期望得到一個java.lang.Boolean類型的值。如果這個參數沒有被設置,那么就允許相對重定向。
    • 'http.protocol.max-redirects':定義了要遵循重定向的最大數量。這個重定向數字的限制意在防止由破碎的服務器端腳本引發的死循環。這個參數期望得到一個java.lang.Integer類型的值。如果這個參數沒有被設置,那么只允許不多余100次重定向。
    • 'http.protocol.allow-circular-redirects':定義環形重定向(重定向到相同路徑)是否被允許。HTTP規范在環形重定向沒有足夠清晰的允許表述,因此這作為可選的是可以開啟的。這個參數期望得到一個java.lang.Boolean類型的值。如果這個參數沒有被設置,那么環形重定向就不允許。
    • 'http.connection-manager.factory-class-name':定義了默認的ClientConnectionManager實現的類型。這個參數期望得到一個java.lang.String類型的值。如果這個參數沒有被設置,對于每個默認的將使用SingleClientConnManager。
    • 'http.virtual-host':定義了在頭部信息Host中使用的虛擬主機名稱,來代替物理主機名稱。這個參數期望得到一個HttpHost類型的值。如果這個參數沒有被設置,那么將會使用目標主機的名稱或IP地址。
    • 'http.default-headers':定義了每次請求默認發送的頭部信息。這個參數期望得到一個包含Header對象的java.util.Collection類型值。
    • 'http.default-host':定義了默認主機。如果目標主機沒有在請求URI(相對URI)中明確指定,那么就使用默認值。這個參數期望得到一個HttpHost類型的值。

    5.3 自動重定向處理

    HttpClient處理所有類型的自動重定向,除了那些由HTTP規范明令禁止的,比如需要用戶干預的。參考其它(狀態碼303)POST和PUT請求重定向轉換為由HTTP規范需要的GET請求。

    5.4 HTTP客戶端和執行上下文

    DefaultHttpClient將HTTP請求視為不變的對象,也從來不會假定在請求執行期間改變。相反,它創建了一個原請求對象私有的可變副本,副本的屬性可以基于執行上下文來更新。因此,如目標主鍵和請求URI的final類型的請求參數可以在請求執行之后,由檢查本地HTTP上下文來決定。

    DefaultHttpClient httpclient = new DefaultHttpClient();
    HttpContext localContext = new BasicHttpContext();
    HttpGet httpget = new HttpGet("http://localhost:8080/");
    HttpResponse response = httpclient.execute(httpget, localContext);
    HttpHost target = (HttpHost) localContext.getAttribute(
    ExecutionContext.HTTP_TARGET_HOST);
    HttpUriRequest req = (HttpUriRequest) localContext.getAttribute(
    ExecutionContext.HTTP_REQUEST);
    System.out.println("Target host: " + target);
    System.out.println("Final request URI: " + req.getURI());
    System.out.println("Final request method: " + req.getMethod());
    http://www.cnblogs.com/loveyakamoz/archive/2011/07/21/2113249.html
    posted @ 2012-09-26 16:44 abin 閱讀(1816) | 評論 (0)編輯 收藏

    第三章 HTTP狀態管理

    原始的HTTP是被設計為無狀態的,面向請求/響應的協議,沒有特殊規定有狀態的,貫穿一些邏輯相關的請求/響應交換的會話。由于HTTP協議變得越來越普及和受歡迎,越來越多的從前沒有打算使用它的系統也開始為應用程序來使用它,比如作為電子商務應用程序的傳輸方式。因此,支持狀態管理就變得非常必要了。

    網景公司,一度成為Web客戶端和服務器軟件開發者的領導方向,在它們基于專有規范的產品中實現了對HTTP狀態管理的支持。之后,網景公司試圖通過發布規范草案來規范這種機制。它們的努力通過RFC標準跟蹤促成了這些規范定義。然而,在很多應用程序中的狀態管理仍然基于網景公司的草案而不兼容官方的規范。很多主要的Web瀏覽器開發者覺得有必要保留那些極大促進標準片段應用程序的兼容性。

    3.1 HTTP cookies

    Cookie是HTTP代理和目標服務器可以交流保持會話的狀態信息的令牌或短包。網景公司的工程師用它來指“魔法小甜餅”和粘住的名字。

    HttpClient使用Cookie接口來代表抽象的cookie令牌。在它的簡單形式中HTTP的cookie幾乎是名/值對。通常一個HTTP的cookie也包含一些屬性,比如版本號,合法的域名,指定cookie應用所在的源服務器URL子集的路徑,cookie的最長有效時間。

    SetCookie接口代表由源服務器發送給HTTP代理的響應中的頭部信息Set-Cookie來維持一個對話狀態。SetCookie2接口和指定的Set-Cookie2方法擴展了SetCookie。

    SetCookie接口和額外的如獲取原始cookie屬性的能力,就像它們由源服務器指定的客戶端特定功能擴展了Cookie接口。這對生成Cookie頭部很重要,因為一些cookie規范需要。Cookie頭部應該包含在Set-Cookie或Set-Cookie2頭部中指定的特定屬性。

    3.1.1 Cookie版本

    Cookie兼容網景公司的草案標準,但是版本0被認為是不符合官方規范的。符合標準的cookie的期望版本是1。HttpClient可以處理基于不同版本的cookie。

    這里有一個重新創建網景公司草案cookie示例:

    BasicClientCookie netscapeCookie = new BasicClientCookie("name", "value");
    netscapeCookie.setVersion(0);
    netscapeCookie.setDomain(".mycompany.com");
    netscapeCookie.setPath("/");

    這是一個重新創建標準cookie的示例。要注意符合標準的cookie必須保留由源服務器發送的所有屬性:

    BasicClientCookie stdCookie = new BasicClientCookie("name", "value");
    stdCookie.setVersion(1);
    stdCookie.setDomain(".mycompany.com");
    stdCookie.setPath("/");
    stdCookie.setSecure(true);
    // 精確設置由服務器發送的屬性
    stdCookie.setAttribute(ClientCookie.VERSION_ATTR, "1");
    stdCookie.setAttribute(ClientCookie.DOMAIN_ATTR, ".mycompany.com");

    這是一個重新創建Set-Cookie2兼容cookie的實例。要注意符合標準的cookie必須保留由源服務器發送的所有屬性:

    BasicClientCookie2 stdCookie = new BasicClientCookie2("name", "value");
    stdCookie.setVersion(1);
    stdCookie.setDomain(".mycompany.com");
    stdCookie.setPorts(new int[] {80,8080});
    stdCookie.setPath("/");
    stdCookie.setSecure(true);
    // 精確設置由服務器發送的屬性
    stdCookie.setAttribute(ClientCookie.VERSION_ATTR, "1");
    stdCookie.setAttribute(ClientCookie.DOMAIN_ATTR, ".mycompany.com");
    stdCookie.setAttribute(ClientCookie.PORT_ATTR, "80,8080");

    3.2 Cookie規范

    CookieSpec接口代表了cookie管理的規范。Cookie管理規范希望如下幾點:
    • 解析的Set-Cookie規則還有可選的Set-Cookie2頭部信息。
    • 驗證解析cookie的規則。
    • 格式化給定主機的Cookie頭部信息,原始端口和路徑。

    HttpClient附帶了一些CookieSpec的實現:

    • 網景公司草案:這個規范符合由網景通訊發布的原始草案規范。應當避免,除非有絕對的必要去兼容遺留代碼。
    • RFC 2109:官方HTTP狀態管理規范并取代的老版本,被RFC 2965取代。
    • RFC 2965:官方HTTP狀態管理規范。
    • 瀏覽器兼容性:這個實現努力去密切模仿(mis)通用Web瀏覽器應用程序的實現。比如微軟的Internet Explorer和Mozilla的FireFox瀏覽器。
    • 最佳匹配:’Meta’(元)cookie規范采用了一些基于又HTTP響應發送的cookie格式的cookie策略。它基本上聚合了以上所有的實現到以一個類中。
    強烈建議使用Best Match策略,讓HttpClient在運行時基于執行上下文采用一些合適的兼容等級。

    3.3 HTTP cookie和狀態管理參數

    這些是用于定制HTTP狀態管理和獨立的cookie規范行為的參數。
    • 'http.protocol.cookie-datepatterns':定義了用于解析非標準的expires屬性的合法日期格式。只是對兼容不符合規定的,仍然使用網景公司草案定義的expires而不使用標準的max-age屬性服務器需要。這個參數期望得到一個java.util.Collection類型的值。集合元素必須是java.lang.String類型,來兼容java.text.SimpleDateFormat的語法。如果這個參數沒有被設置,那么默認的選擇就是CookieSpec實現規范的值。要注意這個參數的應用。
    • 'http.protocol.single-cookie-header':定義了是否cookie應該強制到一個獨立的Cookie請求頭部信息中。否則,每個cookie就被當作分離的Cookie頭部信息來格式化。這個參數期望得到一個java.lang.Boolean類型的值。如果這個參數沒有被設置,那么默認的選擇就是CookieSpec實現規范的值。要注意這個參數僅僅嚴格應用于cookie規范(RFC 2109和RFC 2965)。瀏覽器兼容性和網景公司草案策略將會放置所有的cookie到一個請求頭部信息中。
    • 'http.protocol.cookie-policy':定義了用于HTTP狀態管理的cookie規范的名字。這個參數期望得到一個java.lang.String類型的值。如果這個參數沒有被設置,那么合法的日期格式就是CookieSpec實現規范的值。

    3.4 Cookie規范注冊表

    HttpClient使用CookieSpecRegistry類維護一個可用的cookie規范注冊表。下面的規范對于每個默認都是注冊過的:
    • 兼容性:瀏覽器兼容性(寬松策略)。
    • 網景:網景公司草案。
    • rfc2109:RFC 2109(過時的嚴格策略)。
    • rfc2965:RFC 2965(嚴格策略的標準符合)。
    • best-match:最佳匹配meta(元)策略。

    3.5 選擇cookie策略

    Cookie策略可以在HTTP客戶端被設置,如果需要,在HTTP請求級重寫。
    HttpClient httpclient = new DefaultHttpClient();
    // 對每個默認的強制嚴格cookie策略
    httpclient.getParams().setParameter(
    ClientPNames.COOKIE_POLICY, CookiePolicy.RFC_2965);
    HttpGet httpget = new HttpGet("http://www.broken-server.com/");
    // 對這個請求覆蓋默認策略
    httpget.getParams().setParameter(
    ClientPNames.COOKIE_POLICY, CookiePolicy.BROWSER_COMPATIBILITY);

    3.6 定制cookie策略

    為了實現定制cookie策略,我們應該創建CookieSpec接口的定制實現類,創建一個CookieSpecFactory實現來創建和初始化定制實現的實例并和HttpClient注冊這個工廠。一旦定制實現被注冊了,它可以和標準的cookie實現有相同的活性。
    CookieSpecFactory csf = new CookieSpecFactory() {
    public CookieSpec newInstance(HttpParams params) {
    return new BrowserCompatSpec() {
    @Override
    public void validate(Cookie cookie, CookieOrigin origin)
    throws MalformedCookieException {
    // 這相當簡單
    }
    };
    }
    };
    DefaultHttpClient httpclient = new DefaultHttpClient();
    httpclient.getCookieSpecs().register("easy", csf);
    httpclient.getParams().setParameter(
    ClientPNames.COOKIE_POLICY, "easy");

    3.7 Cookie持久化

    HttpClient可以和任意物理表示的實現了CookieStore接口的持久化cookie存儲一起使用。默認的CookieStore實現稱為BasicClientCookie,這是憑借java.util.ArrayList的一個簡單實現。在BasicClientCookie對象中存儲的cookie當容器對象被垃圾回收機制回收時會丟失。如果需要,用戶可以提供更復雜的實現。
    DefaultHttpClient httpclient = new DefaultHttpClient();
    // 創建一個本地的cookie store實例
    CookieStore cookieStore = new MyCookieStore();
    // 如果需要填充cookie
    BasicClientCookie cookie = new BasicClientCookie("name", "value");
    cookie.setVersion(0);
    cookie.setDomain(".mycompany.com");
    cookie.setPath("/");
    cookieStore.addCookie(cookie);
    // 設置存儲
    httpclient.setCookieStore(cookieStore);

    3.8 HTTP狀態管理和執行上下文

    在HTTP請求執行的過程中,HttpClient添加了下列和狀態管理相關的對象到執行上下文中:
    • 'http.cookiespec-registry':CookieSpecRegistry實例代表了實際的cookie規范注冊表。這個屬性的值設置在本地內容中,優先于默認的。
    • 'http.cookie-spec':CookieSpec實例代表真實的cookie規范。
    • 'http.cookie-origin':CookieOrigin實例代表了真實的源服務器的詳細信息。
    • 'http.cookie-store':CookieStore實例代表了真實的cookie存儲。設置在本地內容中的這個屬性的值優先于默認的。

    本地的HttpContext對象可以被用來定制HTTP狀態管理內容,先于請求執行或在請求執行之后檢查它的狀態:

    HttpClient httpclient = new DefaultHttpClient();
    HttpContext localContext = new BasicHttpContext();
    HttpGet httpget = new HttpGet("http://localhost:8080/");
    HttpResponse response = httpclient.execute(httpget, localContext);
    CookieOrigin cookieOrigin = (CookieOrigin) localContext.getAttribute(
    ClientContext.COOKIE_ORIGIN);
    System.out.println("Cookie origin: " + cookieOrigin);
    CookieSpec cookieSpec = (CookieSpec) localContext.getAttribute(
    ClientContext.COOKIE_SPEC);
    System.out.println("Cookie spec used: " + cookieSpec);

    3.9 每個用戶/線程的狀態管理

    我們可以使用獨立的本地執行上下文來實現對每個用戶(或每個線程)狀態的管理。定義在本地內容中的cookie規范注冊表和cookie存儲將會優先于設置在HTTP客戶端級別中默認的那些。
    HttpClient httpclient = new DefaultHttpClient();
    // 創建cookie store的本地實例
    CookieStore cookieStore = new BasicCookieStore();
    // 創建本地的HTTP內容
    HttpContext localContext = new BasicHttpContext();
    // 綁定定制的cookie store到本地內容中
    localContext.setAttribute(ClientContext.COOKIE_STORE, cookieStore);
    HttpGet httpget = new HttpGet("http://www.google.com/");
    // 作為參數傳遞本地內容
    HttpResponse response = httpclient.execute(httpget, localContext)



    http://www.cnblogs.com/loveyakamoz/archive/2011/07/21/2113246.html
    posted @ 2012-09-26 16:43 abin 閱讀(970) | 評論 (0)編輯 收藏

    第二章 連接管理

    HttpClient有一個對連接初始化和終止,還有在活動連接上I/O操作的完整控制。而連接操作的很多方面可以使用一些參數來控制。

    2.1 連接參數

    這些參數可以影響連接操作:

    • 'http.socket.timeout':定義了套接字的毫秒級超時時間(SO_TIMEOUT),這就是等待數據,換句話說,在兩個連續的數據包之間最大的閑置時間。如果超時時間是0就解釋為是一個無限大的超時時間。這個參數期望得到一個java.lang.Integer類型的值。如果這個參數沒有被設置,那么讀取操作就不會超時(無限大的超時時間)。
    • 'http.tcp.nodelay':決定了是否使用Nagle算法。Nagle算法視圖通過最小化發送的分組數量來節省帶寬。當應用程序希望降低網絡延遲并提高性能時,它們可以關閉Nagle算法(也就是開啟TCP_NODELAY)。數據將會更早發送,增加了帶寬消耗的成文。這個參數期望得到一個java.lang.Boolean類型的值。如果這個參數沒有被設置,那么TCP_NODELAY就會開啟(無延遲)。
    • 'http.socket.buffer-size':決定了內部套接字緩沖使用的大小,來緩沖數據同時接收/傳輸HTTP報文。這個參數期望得到一個java.lang.Integer類型的值。如果這個參數沒有被設置,那么HttpClient將會分配8192字節的套接字緩存。
    • 'http.socket.linger':使用指定的秒數拖延時間來設置SO_LINGER。最大的連接超時值是平臺指定的。值0暗示了這個選項是關閉的。值-1暗示了使用了JRE默認的。這個設置僅僅影響套接字關閉操作。如果這個參數沒有被設置,那么就假設值為-1(JRE默認)。
    • 'http.connection.timeout':決定了直到連接建立時的毫秒級超時時間。超時時間的值為0解釋為一個無限大的時間。這個參數期望得到一個java.lang.Integer類型的值。如果這個參數沒有被設置,連接操作將不會超時(無限大的超時時間)。
    • 'http.connection.stalecheck':決定了是否使用舊的連接檢查。當在一個連接之上執行一個請求而服務器端的連接已經關閉時,關閉舊的連接檢查可能導致在獲得一個I/O錯誤風險時顯著的性能提升(對于每一個請求,檢查時間可以達到30毫秒)。這個參數期望得到一個java.lang.Boolean類型的值。出于性能的關鍵操作,檢查應該被關閉。如果這個參數沒有被設置,那么舊的連接將會在每個請求執行之前執行。
    • 'http.connection.max-line-length':決定了最大請求行長度的限制。如果設置為一個正數,任何HTTP請求行超過這個限制將會引發java.io.IOException異常。負數或零將會關閉這個檢查。這個參數期望得到一個java.lang.Integer類型的值。如果這個參數沒有被設置,那么就不強制進行限制了。
    • 'http.connection.max-header-count':決定了允許的最大HTTP頭部信息數量。如果設置為一個正數,從數據流中獲得的HTTP頭部信息數量超過這個限制就會引發java.io.IOException異常。負數或零將會關閉這個檢查。這個參數期望得到一個java.lang.Integer類型的值。如果這個參數沒有被設置,那么就不
    • 強制進行限制了。
    • 'http.connection.max-status-line-garbage':決定了在期望得到HTTP響應狀態行之前可忽略請求行的最大數量。使用HTTP/1.1持久性連接,這個問題產生的破碎的腳本將會返回一個錯誤的Content-Length(有比指定的字節更多的發送)。不幸的是,在某些情況下,這個不能在錯誤響應后來偵測,只能在下一次之前。所以HttpClient必須以這種方式跳過那些多余的行。這個參數期望得到一個java.lang.Integer類型的值。0是不允許在狀態行之前的所有垃圾/空行。使用java.lang.Integer#MAX_VALUE來設置不限制的數字。如果這個參數沒有被設置那就假設是不限制的。

    2.2 持久連接

    從一個主機向另外一個建立連接的過程是相當復雜的,而且包含了兩個終端之間的很多包的交換,它是相當費時的。連接握手的開銷是很重要的,特別是對小量的HTTP報文。如果打開的連接可以被重用來執行多次請求,那么就可以達到很高的數據吞吐量。

    HTTP/1.1強調HTTP連接默認情況可以被重用于多次請求。HTTP/1.0兼容的終端也可以使用相似的機制來明確地交流它們的偏好來保證連接處于活動狀態,也使用它來處理多個請求。HTTP代理也可以保持空閑連接處于一段時間的活動狀態,防止對相同目標主機的一個連接也許對隨后的請求需要。保持連接活動的能力通常被稱作持久性連接。HttpClient完全支持持久性連接。

    2.3 HTTP連接路由

    HttpClient能夠直接或通過路由建立連接到目標主機,這會涉及多個中間連接,也被稱為跳。HttpClient區分路由和普通連接,通道和分層。通道連接到目標主機的多個中間代理的使用也稱作是代理鏈。

    普通路由由連接到目標或僅第一次的代理來創建。通道路由通過代理鏈到目標連接到第一通道來建立。沒有代理的路由不是通道的,分層路由通過已存在連接的分層協議來建立。協議僅僅可以在到目標的通道上或在沒有代理的直接連接上分層。

    2.3.1 路由計算

    RouteInfo接口代表關于最終涉及一個或多個中間步驟或跳的目標主機路由的信息。HttpRoute是RouteInfo的具體實現,這是不能改變的(是不變的)。HttpTracker是可變的RouteInfo實現,由HttpClient在內部使用來跟蹤到最大路由目標的剩余跳數。HttpTracker可以在成功執行向路由目標的下一跳之后更新。HttpRouteDirector是一個幫助類,可以用來計算路由中的下一跳。這個類由HttpClient在內部使用。

    HttpRoutePlanner是一個代表計算到基于執行上下文到給定目標完整路由策略的接口。HttpClient附帶兩個默認的HttpRoutePlanner實現。ProxySelectorRoutePlanner是基于java.net.ProxySelector的。默認情況下,它會從系統屬性中或從運行應用程序的瀏覽器中選取JVM的代理設置。DefaultHttpRoutePlanner實現既不使用任何Java系統屬性,也不使用系統或瀏覽器的代理設置。它只基于HTTP如下面描述的參數計算路由。

    2.3.2 安全HTTP連接

    如果信息在兩個不能由非認證的第三方進行讀取或修改的終端之間傳輸,HTTP連接可以被認為是安全的。SSL/TLS協議是用來保證HTTP傳輸安全使用最廣泛的技術。而其它加密技術也可以被使用。通常來說,HTTP傳輸是在SSL/TLS加密連接之上分層的。

    2.4 HTTP路由參數

    這些參數可以影響路由計算:
    • 'http.route.default-proxy':定義可以被不使用JRE設置的默認路由規劃者使用的代理主機。這個參數期望得到一個HttpHost類型的值。如果這個參數沒有被設置,那么就會嘗試直接連接到目標。
    • 'http.route.local-address':定義一個本地地址由所有默認路由規劃者來使用。有多個網絡接口的機器中,這個參數可以被用于從連接源中選擇網絡接口。這個參數期望得到一個java.net.InetAddress類型的值。如果這個參數沒有被設置,將會自動使用本地地址。
    • 'http.route.forced-route':定義一個由所有默認路由規劃者使用的強制路由。代替了計算路由,給定的強制路由將會被返回,盡管它指向一個完全不同的目標主機。這個參數期望得到一個HttpRoute類型的值。如果這個參數沒有被設置,那么就使用默認的規則建立連接到目標服務器。

    2.5 套接字工廠

    LayeredSocketFactory是SocketFactory接口的擴展。分層的套接字工廠可HTTP連接內部使用java.net.Socket對象來處理數據在線路上的傳輸。它們依賴SocketFactory接口來創建,初始化和連接套接字。這會使得HttpClient的用戶可以提供在運行時指定套接字初始化代碼的應用程序。PlainSocketFactory是創建和初始化普通的(不加密的)套接字的默認工廠。

    創建套接字的過程和連接到主機的過程是不成對的,所以套接字在連接操作封鎖時可以被關閉。

    PlainSocketFactory sf = PlainSocketFactory.getSocketFactory();
    Socket socket = sf.createSocket();
    HttpParams params = new BasicHttpParams();
    params.setParameter(CoreConnectionPNames.CONNECTION_TIMEOUT, 1000L);
    sf.connectSocket(socket, "locahost", 8080, null, -1, params);

    2.5.1 安全套接字分層

    LayeredSocketFactory是SocketFactory接口的擴展。分層的套接字工廠可以創建在已經存在的普通套接字之上的分層套接字。套接字分層主要通過代理來創建安全的套接字。HttpClient附帶實現了SSL/TLS分層的SSLSocketFactory。請注意HttpClient不使用任何自定義加密功能。它完全依賴于標準的Java密碼學(JCE)和安全套接字(JSEE)擴展。

    2.5.2 SSL/TLS的定制

    HttpClient使用SSLSocketFactory來創建SSL連接。SSLSocketFactory允許高度定制。它可以使用javax.net.ssl.SSLContext的實例作為參數,并使用它來創建定制SSL連接。

    TrustManager easyTrustManager = new X509TrustManager() {
    @Override
    public void checkClientTrusted(X509Certificate[] chain,
    String authType) throws CertificateException {
    // 哦,這很簡單!
    }
    @Override
    public void checkServerTrusted(X509Certificate[] chain,
    String authType) throws CertificateException {
    //哦,這很簡單!
    }
    @Override
    public X509Certificate[] getAcceptedIssuers() {
    return null;
    }
    };
    SSLContext sslcontext = SSLContext.getInstance("TLS");
    sslcontext.init(null, new TrustManager[] { easyTrustManager }, null);
    SSLSocketFactory sf = new SSLSocketFactory(sslcontext);
    SSLSocket socket = (SSLSocket) sf.createSocket();
    socket.setEnabledCipherSuites(new String[] { "SSL_RSA_WITH_RC4_128_MD5" });
    HttpParams params = new BasicHttpParams();
    params.setParameter(CoreConnectionPNames.CONNECTION_TIMEOUT, 1000L);
    sf.connectSocket(socket, "locahost", 443, null, -1, params);
    SSLSocketFactory的定制暗示出一定程度SSL/TLS協議概念的熟悉,這個詳細的解釋超出了本文檔的范圍。請參考Java的安全套接字擴展[http://java.sun.com/j2se/1.5.0/docs/guide/
    security/jsse/JSSERefGuide.html],這是javax.net.ssl.SSLContext和相關工具的詳細描述。

    2.5.3 主機名驗證

    除了信任驗證和客戶端認證在SSL/TLS協議級上進行,一旦連接建立之后,HttpClient能可選地驗證目標主機名匹配存儲在服務器的X.509認證中的名字。這個認證可以提供額外的服務器信任材料的真實保證。X509主機名驗證接口代表了主機名驗證的策略。HttpClient附帶了3個X509主機名驗證器。很重要的一點是:主機名驗證不應該混淆SSL信任驗證。
    • StrictHostnameVerifier:嚴格的主機名驗證在Sun Java 1.4,Sun Java 5和Sun Java 6中是相同的。而且也非常接近IE6。這個實現似乎是兼容RFC 2818處理通配符的。主機名必須匹配第一個CN或任意的subject-alt。在CN和其它任意的subject-alt中可能會出現通配符。
    • BrowserCompatHostnameVerifier:主機名驗證器和Curl和Firefox的工作方式是相同的。主機名必須匹配第一個CN或任意的subject-alt。在CN和其它任意的subject-alt中可能會出現通配符。BrowserCompatHostnameVerifier和StrictHostnameVerifier的唯一不同是使用BrowserCompatHostnameVerifier匹配所有子域的通配符(比如”*.foo.com”),包括”a.b.foo.com”。
    • AllowAllHostnameVerifier:這個主機名驗證器基本上是關閉主機名驗證的。這個實現是一個空操作,而且不會拋出javax.net.ssl.SSLException異常。

    每一個默認的HttpClient使用BrowserCompatHostnameVerifier的實現。如果需要的話,它可以指定不同的主機名驗證器實現。

    SSLSocketFactory sf = new SSLSocketFactory(SSLContext.getInstance("TLS"));
    sf.setHostnameVerifier(SSLSocketFactory.STRICT_HOSTNAME_VERIFIER);

    2.6 協議模式

    Scheme類代表了一個協議模式,比如“http”或“https”同時包含一些協議屬性,比如默認端口,用來為給定協議創建java.net.Socket實例的套接字工廠。SchemeRegistry類用來維持一組Scheme,當去通過請求URI建立連接時,HttpClient可以從中選擇:

    Scheme http = new Scheme("http", PlainSocketFactory.getSocketFactory(), 80);
    SSLSocketFactory sf = new SSLSocketFactory(SSLContext.getInstance("TLS"));
    sf.setHostnameVerifier(SSLSocketFactory.STRICT_HOSTNAME_VERIFIER);
    Scheme https = new Scheme("https", sf, 443);
    SchemeRegistry sr = new SchemeRegistry();
    sr.register(http);
    sr.register(https);

    2.7 HttpClient代理配置

    盡管HttpClient了解復雜的路由模式和代理鏈,它僅支持簡單直接的或開箱的跳式代理連接。

    告訴HttpClient通過代理去連接到目標主機的最簡單方式是通過設置默認的代理參數:

    DefaultHttpClient httpclient = new DefaultHttpClient();
    HttpHost proxy = new HttpHost("someproxy", 8080);
    httpclient.getParams().setParameter(ConnRoutePNames.DEFAULT_PROXY, proxy);

    也可以構建HttpClient使用標準的JRE代理選擇器來獲得代理信息:

    DefaultHttpClient httpclient = new DefaultHttpClient();
    ProxySelectorRoutePlanner routePlanner = new ProxySelectorRoutePlanner(
    httpclient.getConnectionManager().getSchemeRegistry(),
    ProxySelector.getDefault());
    httpclient.setRoutePlanner(routePlanner);

    另外一種選擇,可以提供一個定制的RoutePlanner實現來獲得HTTP路由計算處理上的復雜的控制:

    DefaultHttpClient httpclient = new DefaultHttpClient();
    httpclient.setRoutePlanner(new HttpRoutePlanner() {
    public HttpRoute determineRoute(HttpHost target,
    HttpRequest request,
    HttpContext context) throws HttpException {
    return new HttpRoute(target, null, new HttpHost("someproxy", 8080),
    "https".equalsIgnoreCase(target.getSchemeName()));
    }
    });

    2.8 HTTP連接管理器

    2.8.1 連接操作器

    連接操作是客戶端的低層套接字或可以通過外部實體,通常稱為連接操作的被操作的狀態的連接。OperatedClientConnection接口擴展了HttpClientConnection接口而且定義了額外的控制連接套接字的方法。ClientConnectionOperator接口代表了創建實例和更新那些對象低層套接字的策略。實現類最有可能利用SocketFactory來創建java.net.Socket實例。ClientConnectionOperator接口可以讓HttpClient的用戶提供一個連接操作的定制策略和提供可選實現OperatedClientConnection接口的能力。

    2.8.2 管理連接和連接管理器

    HTTP連接是復雜的,有狀態的,線程不安全的對象需要正確的管理以便正確地執行功能。HTTP連接在同一時間僅僅只能由一個執行線程來使用。HttpClient采用一個特殊實體來管理訪問HTTP連接,這被稱為HTTP連接管理器,代表了ClientConnectionManager接口。一個HTTP連接管理器的目的是作為工廠服務于新的HTTP連接,管理持久連接和同步訪問持久連接來確保同一時間僅有一個線程可以訪問一個連接。

    內部的HTTP連接管理器和OperatedClientConnection實例一起工作,但是它們為服務消耗器ManagedClientConnection提供實例。ManagedClientConnection扮演連接之上管理狀態控制所有I/O操作的OperatedClientConnection實例的包裝器。它也抽象套接字操作,提供打開和更新去創建路由套接字便利的方法。ManagedClientConnection實例了解產生它們到連接管理器的鏈接,而且基于這個事實,當不再被使用時,它們必須返回到管理器。ManagedClientConnection類也實現了ConnectionReleaseTrigger接口,可以被用來觸發釋放連接返回給管理器。一旦釋放連接操作被觸發了,被包裝的連接從ManagedClientConnection包裝器中脫離,OperatedClientConnection實例被返回給管理器。盡管服務消耗器仍然持有ManagedClientConnection實例的引用,它也不再去執行任何I/O操作或有意無意地改變的OperatedClientConnection狀態。

    這里有一個從連接管理器中獲取連接的示例:

    HttpParams params = new BasicHttpParams();
    Scheme http = new Scheme("http", PlainSocketFactory.getSocketFactory(), 80);
    SchemeRegistry sr = new SchemeRegistry();
    sr.register(http);
    ClientConnectionManager connMrg = new SingleClientConnManager(params, sr);
    // 請求新連接。這可能是一個很長的過程。
    ClientConnectionRequest connRequest = connMrg.requestConnection(
    new HttpRoute(new HttpHost("localhost", 80)), null);
    // 等待連接10秒
    ManagedClientConnection conn = connRequest.getConnection(10, TimeUnit.SECONDS);
    try {
    // 用連接在做有用的事情。當完成時釋放連接。
    conn.releaseConnection();
    } catch (IOException ex) {
    // 在I/O error之上終止連接。
    conn.abortConnection();
    throw ex;
    }

    如果需要,連接請求可以通過調用來ClientConnectionRequest#abortRequest()方法過早地中斷。這會解鎖在ClientConnectionRequest#getConnection()方法中被阻止的線程。

    一旦響應內容被完全消耗后,BasicManagedEntity包裝器類可以用來保證自動釋放低層的連接。HttpClient內部使用這個機制來實現透明地對所有從HttpClient#execute()方法中獲得響應釋放連接:

    ClientConnectionRequest connRequest = connMrg.requestConnection(
    new HttpRoute(new HttpHost("localhost", 80)), null);
    ManagedClientConnection conn = connRequest.getConnection(10, TimeUnit.SECONDS);
    try {
    BasicHttpRequest request = new BasicHttpRequest("GET", "/");
    conn.sendRequestHeader(request);
    HttpResponse response = conn.receiveResponseHeader();
    conn.receiveResponseEntity(response);
    HttpEntity entity = response.getEntity();
    if (entity != null) {
    BasicManagedEntity managedEntity = new BasicManagedEntity(entity, conn, true);
    // 替換實體
    response.setEntity(managedEntity);
    }
    // 使用響應對象做有用的事情。當響應內容被消耗后這個連接將會自動釋放。
    } catch (IOException ex) {
    //在I/O error之上終止連接。
    conn.abortConnection();
    throw ex;
    }

    2.8.3 簡單連接管理器

    SingleClientConnManager是一個簡單的連接管理器,在同一時間它僅僅維護一個連接。盡管這個類是線程安全的,但它應該被用于一個執行線程。SingleClientConnManager對于同一路由的后續請求會盡量重用連接。而如果持久連接的路由不匹配連接請求的話,它也會關閉存在的連接之后對給定路由再打開一個新的。如果連接已經被分配,將會拋出java.lang.IllegalStateException異常。

    對于每個默認連接,HttpClient使用SingleClientConnManager。

    2.8.4 連接池管理器

    ThreadSafeClientConnManager是一個復雜的實現來管理客戶端連接池,它也可以從多個執行線程中服務連接請求。對每個基本的路由,連接都是池管理的。對于路由的請求,管理器在池中有可用的持久性連接,將被從池中租賃連接服務,而不是創建一個新的連接。

    ThreadSafeClientConnManager維護每個基本路由的最大連接限制。每個默認的實現對每個給定路由將會創建不超過兩個的并發連接,而總共也不會超過20個連接。對于很多真實的應用程序,這個限制也證明很大的制約,特別是他們在服務中使用HTTP作為傳輸協議。連接限制,也可以使用HTTP參數來進行調整。

    這個示例展示了連接池參數是如何來調整的:

    HttpParams params = new BasicHttpParams();
    // 增加最大連接到200
    ConnManagerParams.setMaxTotalConnections(params, 200);
    // 增加每個路由的默認最大連接到20
    ConnPerRouteBean connPerRoute = new ConnPerRouteBean(20);
    // 對localhost:80增加最大連接到50
    HttpHost localhost = new HttpHost("locahost", 80);
    connPerRoute.setMaxForRoute(new HttpRoute(localhost), 50);
    ConnManagerParams.setMaxConnectionsPerRoute(params, connPerRoute);
    SchemeRegistry schemeRegistry = new SchemeRegistry();
    schemeRegistry.register(
    new Scheme("http", PlainSocketFactory.getSocketFactory(), 80));
    schemeRegistry.register(
    new Scheme("https", SSLSocketFactory.getSocketFactory(), 443));
    ClientConnectionManager cm = new ThreadSafeClientConnManager(params, schemeRegistry);
    HttpClient httpClient = new DefaultHttpClient(cm, params);

    2.8.5 連接管理器關閉

    當一個HttpClient實例不再需要時,而且即將走出使用范圍,那么關閉連接管理器來保證由管理器保持活動的所有連接被關閉,由連接分配的系統資源被釋放是很重要的。

    DefaultHttpClient httpclient = new DefaultHttpClient();
    HttpGet httpget = new HttpGet("http://www.google.com/");
    HttpResponse response = httpclient.execute(httpget);
    HttpEntity entity = response.getEntity();
    System.out.println(response.getStatusLine());
    if (entity != null) {
    entity.consumeContent();
    }
    httpclient.getConnectionManager().shutdown();

    2.9 連接管理參數

    這些是可以用于定制標準HTTP連接管理器實現的參數:
    • 'http.conn-manager.timeout':定義了當從ClientConnectionManager中檢索ManagedClientConnection實例時使用的毫秒級的超時時間。這個參數期望得到一個java.lang.Long類型的值。如果這個參數沒有被設置,連接請求就不會超時(無限大的超時時間)。
    • 'http.conn-manager.max-per-route':定義了每個路由連接的最大數量。這個限制由客戶端連接管理器來解釋,而且應用于獨立的管理器實例。這個參數期望得到一個ConnPerRoute類型的值。
    • 'http.conn-manager.max-total':定義了總共連接的最大數目。這個限制由客戶端連接管理器來解釋,而且應用于獨立的管理器實例。這個參數期望得到一個java.lang.Integer類型的值。

    2.10 多線程執行請求

    當配備連接池管理器時,比如ThreadSafeClientConnManager,HttpClient可以同時被用來執行多個請求,使用多線程執行。

    ThreadSafeClientConnManager將會分配基于它的配置的連接。如果對于給定路由的所有連接都被租出了,那么連接的請求將會阻塞,直到一個連接被釋放回連接池。它可以通過設置'http.conn-manager.timeout'為一個正數來保證連接管理器不會在連接請求執行時無限期的被阻塞。如果連接請求不能在給定的時間周期內被響應,將會拋出ConnectionPoolTimeoutException異常。

    HttpParams params = new BasicHttpParams();
    SchemeRegistry schemeRegistry = new SchemeRegistry();
    schemeRegistry.register(
    new Scheme("http", PlainSocketFactory.getSocketFactory(), 80));
    ClientConnectionManager cm = new ThreadSafeClientConnManager(params, schemeRegistry);
    HttpClient httpClient = new DefaultHttpClient(cm, params);
    // 執行GET方法的URI
    String[] urisToGet = {
    "http://www.domain1.com/",
    "http://www.domain2.com/",
    "http://www.domain3.com/",
    "http://www.domain4.com/"
    };
    // 為每個URI創建一個線程
    GetThread[] threads = new GetThread[urisToGet.length];
    for (int i = 0; i < threads.length; i++) {
    HttpGet httpget = new HttpGet(urisToGet[i]);
    threads[i] = new GetThread(httpClient, httpget);
    }
    // 開始執行線程
    for (int j = 0; j < threads.length; j++) {
    threads[j].start();
    }
    // 合并線程
    for (int j = 0; j < threads.length; j++) {
    threads[j].join();
    }
     
    static class GetThread extends Thread {
    private final HttpClient httpClient;
    private final HttpContext context;
    private final HttpGet httpget;
    public GetThread(HttpClient httpClient, HttpGet httpget) {
    this.httpClient = httpClient;
    this.context = new BasicHttpContext();
    this.httpget = httpget;
    }
    @Override
    public void run() {
    try {
    HttpResponse response = this.httpClient.execute(this.httpget, this.context);
    HttpEntity entity = response.getEntity();
    if (entity != null) {
    // 對實體做些有用的事情...
    // 保證連接能釋放回管理器
    entity.consumeContent();
    }
    } catch (Exception ex) {
    this.httpget.abort();
    }
    }
    }

    2.11 連接收回策略

    一個經典的阻塞I/O模型的主要缺點是網絡套接字僅當I/O操作阻塞時才可以響應I/O事件。當一個連接被釋放返回管理器時,它可以被保持活動狀態而卻不能監控套接字的狀態和響應任何I/O事件。如果連接在服務器端關閉,那么客戶端連接也不能去偵測連接狀態中的變化和關閉本端的套接字去作出適當響應。

    HttpClient通過測試連接是否是過時的來嘗試去減輕這個問題,這已經不再有效了,因為它已經在服務器端關閉了,之前使用執行HTTP請求的連接。過時的連接檢查也并不是100%的穩定,反而對每次請求執行還要增加10到30毫秒的開銷。唯一可行的而不涉及到每個對空閑連接的套接字模型線程解決方案,是使用專用的監控線程來收回因為長時間不活動而被認為是過期的連接。監控線程可以周期地調用ClientConnectionManager#closeExpiredConnections()方法來關閉所有過期的連接,從連接池中收回關閉的連接。它也可以選擇性調用ClientConnectionManager#closeIdleConnections()方法來關閉所有已經空閑超過給定時間周期的連接。

    public static class IdleConnectionMonitorThread extends Thread {
    private final ClientConnectionManager connMgr;
    private volatile boolean shutdown;
    public IdleConnectionMonitorThread(ClientConnectionManager connMgr) {
    super();
    this.connMgr = connMgr;
    }
    @Override
    public void run() {
    try {
    while (!shutdown) {
    synchronized (this) {
    wait(5000);
    // 關閉過期連接
    connMgr.closeExpiredConnections();
    // 可選地,關閉空閑超過30秒的連接
    connMgr.closeIdleConnections(30, TimeUnit.SECONDS);
    }
    }
    } catch (InterruptedException ex) {
    // 終止
    }
    }
    public void shutdown() {
    shutdown = true;
    synchronized (this) {
    notifyAll();
    }
    }
    }

    2.12 連接保持活動的策略

    HTTP規范沒有確定一個持久連接可能或應該保持活動多長時間。一些HTTP服務器使用非標準的頭部信息Keep-Alive來告訴客戶端它們想在服務器端保持連接活動的周期秒數。如果這個信息可用,HttClient就會利用這個它。如果頭部信息Keep-Alive在響應中不存在,HttpClient假設連接無限期的保持活動。然而許多現實中的HTTP服務器配置了在特定不活動周期之后丟掉持久連接來保存系統資源,往往這是不通知客戶端的。如果默認的策略證明是過于樂觀的,那么就會有人想提供一個定制的保持活動策略。

    DefaultHttpClient httpclient = new DefaultHttpClient();
    httpclient.setKeepAliveStrategy(new ConnectionKeepAliveStrategy() {
    public long getKeepAliveDuration(HttpResponse response, HttpContext context) {
    // 兌現'keep-alive'頭部信息
    HeaderElementIterator it = new BasicHeaderElementIterator(
    response.headerIterator(HTTP.CONN_KEEP_ALIVE));
    while (it.hasNext()) {
    HeaderElement he = it.nextElement();
    String param = he.getName();
    String value = he.getValue();
    if (value != null && param.equalsIgnoreCase("timeout")) {
    try {
    return Long.parseLong(value) * 1000;
    } catch(NumberFormatException ignore) {
    }
    }
    }
    HttpHost target = (HttpHost) context.getAttribute(
    ExecutionContext.HTTP_TARGET_HOST);
    if ("www.naughty-server.com".equalsIgnoreCase(target.getHostName())) {
    // 只保持活動5秒
    return 5 * 1000;
    } else {
    // 否則保持活動30秒
    return 30 * 1000;
    }
    }
    }); 

     



    轉載自:http://www.cnblogs.com/loveyakamoz/archive/2011/07/21/2112832.html
    posted @ 2012-09-26 16:42 abin 閱讀(3459) | 評論 (0)編輯 收藏

         摘要: 前言 超文本傳輸協議(HTTP)也許是當今互聯網上使用的最重要的協議了。Web服務,有網絡功能的設備和網絡計算的發展,都持續擴展了HTTP協議的角色,超越了用戶使用的Web瀏覽器范疇,同時,也增加了需要HTTP協議支持的應用程序的數量。 盡管java.net包提供了基本通過HTTP訪問資源的功能,但它沒有提供全面的靈活性和其它很多應用程序需要的功能。HttpClient就是尋求彌補這項空白...  閱讀全文
    posted @ 2012-09-26 16:41 abin 閱讀(14936) | 評論 (0)編輯 收藏

    簡要記錄主要步驟備忘

    1、進入到jdk下的bin目錄

    2、輸入如下指令

    keytool -v -genkey -alias tomcat -keyalg RSA -keystore d:/tomcat.keystore  -validity 36500

    附:

    d:/tomcat.keystore是將生成的tomcat.keystore放到d盤根目錄下。

    "-validity 36500含義是證書有效期,36500表示100年,默認值是90

    注意若要放到c盤,在win7系統下,需要以管理員身份進入到命令行中進行操作,否則是無法創建tomcat.keystore的。本例放到d盤下。
    如何以管理員身份進入到命令行下呢?開始->搜索框中輸入cmd->等待(注意不回車)->出現cmd.exe->右鍵“以管理員身份運行”即可。

    3、輸入keystore密碼

    密碼任意,此處以123456為例,要記住這個密碼,之后在進行server.xml配置時需要使用。

    4、輸入名字、組織單位、組織、市、省、國家等信息

    注意事項:
    A、Enter keystore password:此處需要輸入大于6個字符的字符串
    B、“What is your first and last name?”這是必填項,并且必須是TOMCAT部署主機的域名或者IP[如:gbcom.com 或者 10.1.25.251],就是你將來要在瀏覽器中輸入的訪問地址
    C、“What is the name of your organizational unit?”、“What is the name of your organization?”、“What is the name of your City or Locality?”、“What is the name of your State or Province?”、“What is the two-letter country code for this unit?”可以按照需要填寫也可以不填寫直接回車,在系統詢問“correct?”時,對照輸入信息,如果符合要求則使用鍵盤輸入字母“y”,否則輸入“n”重新填寫上面的信息
    D、Enter key password for <tomcat>,這項較為重要,會在tomcat配置文件中使用,建議輸入與keystore的密碼一致,設置其它密碼也可以
    l  完成上述輸入后,直接回車則在你在第二步中定義的位置找到生成的文件

    5、輸入之后會出現確認的提示

    此時輸入y,并回車。此時創建完成keystore。
    進入到D盤根目錄下可以看到已經生成的tomcat.xml

    6、進入tomcat文件夾
    找到conf目錄下的sever.xml并進行編輯

    7、編輯
      <Connector port="8443" protocol="HTTP/1.1" SSLEnabled="true"
         maxThreads="150" scheme="https" secure="true"
         clientAuth="false" keystoreFile="D:/AppServer/Tomcat/apache-tomcat-6.0.32/conf/tomcat.keystore"
         keystorePass="deleiguo" sslProtocol="TLS" />
    注:
    方框中的keystore的密碼,就是剛才我們設置的“123456”.

    編輯完成后關閉并保存sever.xml

    8、Tomcat啟動成功后,使用https://127.0.0.1:8443 訪問頁面

    頁面成功打開即tomcat下的https配置成功。

     

    9、應用程序HTTP自動跳轉到HTTPS

    在應用程序中web.xml中加入:

    <security-constraint> 
           <web-resource-collection > 
                  <web-resource-name >SSL</web-resource-name> 
                  <url-pattern>/*</url-pattern> 
           </web-resource-collection>
                                 
           <user-data-constraint> 
                  <transport-guarantee>CONFIDENTIAL</transport-guarantee> 
           </user-data-constraint> 
    </security-constraint>
     
    10、生成安全證書文件
    keytool -export -alias tomcat -file D:/file.cer -keystore d:/tomcat.keystore -validity 36500
    然后輸入d:/tomcat.keystore中的keystore密碼
     
    -file D:/file.cer 即為生成的cer文件,可直接點擊安裝
     
    11、注意事項:
    (1)    生成證書的時間,如果IE客戶端所在機器的時間早于證書生效時間,或者晚于有效時間,IE會提示“該安全證書已到期或還未生效”
    (2)    如果IE提示“安全證書上的名稱無效或者與站點名稱不匹配”,則是由生成證書時填寫的服務器所在主機的域名“您的名字與姓氏是什么?”/“What is your first and last name?”不正確引起的
     
    12、遺留問題:
    (1)如果AC主機不能通過域名查找,必須使用IP,但是這個IP只有在配置后才能確定,這樣證書就必須在AC確定IP地址后才能生成
    (2)證書文件只能綁定一個IP地址,假設有10.1.25.250 和 192.168.1.250 兩個IP地址,在證書生成文件時,如使用了10.1.25.250,通過IE就只能使用10.1.25.250 來訪問AC-WEB,192.168.1.250是無法訪問AC-WEB的。
    posted @ 2012-09-26 16:34 abin 閱讀(15562) | 評論 (0)編輯 收藏

    http://blog.sina.com.cn/s/blog_6cfb6b090100ve92.html 

    http://www.cnblogs.com/lanzi/archive/2011/03/30/1999790.html 


    posted @ 2012-09-25 00:37 abin 閱讀(344) | 評論 (0)編輯 收藏

    https一般來說有單項SSL和雙向SSL連接之分。

     

    單項SSL連接,也就是只是客戶端驗證服務器證書。tomcat中clientAuth="false"的時候,HTTPS單向驗證如下:

    import java.io.BufferedReader;
    import java.io.InputStreamReader;
    import java.io.OutputStream;
    import java.net.URL;
    import java.util.Date;
    import javax.net.ssl.HostnameVerifier;
    import javax.net.ssl.HttpsURLConnection;
    import javax.net.ssl.SSLSession;
    import org.apache.commons.logging.Log;
    import org.apache.commons.logging.LogFactory;

    public class ClientSendData {
        static Log log = LogFactory.getLog(ClientSendData.class);
        // 客戶端信任的證書
        private String sslTrustStore;
        private String sslTrustStorePassword;
        private String Url;

        //初始化數據
        public ClientSendData() {
            sslTrustStore = "D:/ssl/clientTrust.jks";
            sslTrustStorePassword = "123456";
            Url = "https://test.yihaodian.com:8443/ims/feedbackToPingAn_getData.action";
        }

        public String sendData(String data) {
            String receivedData = null;
            try {
                //設置系統參數
                System.setProperty("javax.net.ssl.trustStore", sslTrustStore);
                System.setProperty("javax.net.ssl.trustStorePassword",
                        sslTrustStorePassword);
                receivedData = send(Url, data);
            } catch (Exception e) {
                e.printStackTrace();
            }
            return receivedData;
        }

        public static String send(String sendurl, String sendData)
                throws Exception {
            URL url = new URL(sendurl);
            HostnameVerifier hv = new HostnameVerifier() {
                public boolean verify(String urlHostName, SSLSession session) {
                    return true;
                }
            };
            System.setProperty("java.protocol.handler.pkgs","sun.net.www.protocol");
            HttpsURLConnection.setDefaultHostnameVerifier(hv);
            Date current = new Date(System.currentTimeMillis());
            log.info("begint to open connection at " + current);
            HttpsURLConnection connection = (HttpsURLConnection) url.openConnection();
            Date end = new Date(System.currentTimeMillis());
            log.info("open connection ok at " + end + ",cost:"+ (end.getTime() - current.getTime()));
            connection.setRequestProperty("Content-Type", "text/xml");
            connection.setDoOutput(true);
            connection.setDoInput(true);
            connection.setRequestMethod("POST");
            connection.setUseCaches(false);
            connection.setReadTimeout(30000);
            byte data[] = sendData.getBytes();
            current = new Date(System.currentTimeMillis());
            log.info("[SSLIX]notifyEai,begint to write data at " + current);
            OutputStream out = connection.getOutputStream();
            out.write(data);
            end = new Date(System.currentTimeMillis());
            log.info("write data ok at " + end + ",cost:"
                    + (end.getTime() - current.getTime()));
            StringBuffer receivedData = new StringBuffer();
            current = new Date(System.currentTimeMillis());
            log.info("begint to read data at " + current);
            InputStreamReader inReader = new InputStreamReader(connection
                    .getInputStream(), "UTF-8");
            BufferedReader aReader = new BufferedReader(inReader);
            String aLine;
            while ((aLine = aReader.readLine()) != null) {
                receivedData.append(aLine);
            }
            end = new Date(System.currentTimeMillis());
            log.info("read data ok at " + end + ",cost:"
                    + (end.getTime() - current.getTime()));

            log.info("開始返回狀態碼");
            Integer statusCode = connection.getResponseCode();
            log.info("返回狀態碼:" + statusCode);
            aReader.close();
            connection.disconnect();
            return receivedData.toString();
        }

        public static void main(String[] args) {
            ClientSendData t = new ClientSendData();
            t.sendData("測試SSL單項連接,向服務端發送數據!");
        }
    }

    單項認證時,只需要設置客戶端信任的證書庫就行。但是當是雙向認證時,還需要設置客戶端密鑰庫密碼。

    HTTPS雙向驗證代碼如下:

    public class ClientSendData {
        static Log log = LogFactory.getLog(EaiChannel.class);
        //客戶端密鑰庫
        private String sslKeyStorePath;
        private String sslKeyStorePassword;
        private String sslKeyStoreType;
        // 客戶端信任的證書
        private String sslTrustStore;
        private String sslTrustStorePassword;
        private String eaiUrl;

        //初始化數據
        public ClientSendData() {
            sslKeyStorePath = "D:/ssl/clientKeys.jks";
            sslKeyStorePassword     = "123456";
            sslKeyStoreType = "JKS"; //密鑰庫類型,有JKS PKCS12等
            sslTrustStore = "D:/ssl/clientTrust.jks";
            sslTrustStorePassword = "123456";
            eaiUrl = "https://test.yihaodian.com:8443/ims/feedbackToPingAn_getData.action";
        }

        public String sendData(String data) {
            String receivedData = null;
            try {
                
                 System.setProperty("javax.net.ssl.keyStore", sslKeyStorePath);
                 System.setProperty("javax.net.ssl.keyStorePassword",sslKeyStorePassword);
                 System.setProperty("javax.net.ssl.keyStoreType", sslKeyStoreType);
                //設置系統參數
                System.setProperty("javax.net.ssl.trustStore", sslTrustStore);
                System.setProperty("javax.net.ssl.trustStorePassword",
                        sslTrustStorePassword);
                receivedData = send(eaiUrl, data);
            } catch (Exception e) {
                e.printStackTrace();
            }
            return receivedData;
        }

        public static String send(String sendurl, String sendData)
                throws Exception {
            //和上面一樣
        }

        public static void main(String[] args) {
            ClientSendData t = new ClientSendData();
            t.sendData("測試SSL雙項連接,向服務端發送數據!");
        }
    }


    下面來說說可能會遇到的異常:

    1. java.security.NoSuchAlgorithmException

     

    一般來說是密鑰庫類型不對,如上面的sslKeyStoreType = "JKS" 卻寫成PKCS12。

     

    也有可能是證書的問題。

     

    2. java.net.UnknownHostException

     

    服務端地址不對。

     

    3.java.net.SocketException: Unexpected end of file from server

     

    這個異常和客戶端沒有關系,說明已經發送成功。是服務端的問題。有可能是防火墻的原因,也可能是服務端沒處理客戶端的響應。

    另外有人說當URL過長時也會發生此錯誤,當使用URL發送數據時,可以參考此意見。

     

    4.java.io.IOException:server returned HTTP response code :500

     

     

    這個異常是服務端代碼的問題。服務端相應代碼執行時拋出了異常。

     

     

    最后 如果返回的狀態碼是200 ,表示成功。


     

     

    posted @ 2012-09-23 22:31 abin 閱讀(9150) | 評論 (1)編輯 收藏

    另一個新的jetty eclisep插件

    通過該插件可以直接在Eclipse環境中啟動、停止 Jetty ,同時進行在線調試而無需重啟服務。

    eclipse 更新地址:http://run-jetty-run.googlecode.com/svn/trunk/updatesite/

    項目主頁:http://www.open-open.com/lib/view/home/1328164665703

    posted @ 2012-09-21 00:27 abin 閱讀(1407) | 評論 (0)編輯 收藏

    1、Connection創建類

    package com.abin.lee.db.oracle.batch;

    import java.sql.Connection;
    import java.sql.DriverManager;

    public class OracleConnection {
     private static ThreadLocal<Connection> threadLocal = new ThreadLocal<Connection>();
     private static final String URL="jdbc:oracle:thin:@localhost:1521:XE";
     private static final String USER="abin";
     private static final String PWD="abin";
     private static final String DRIVER="oracle.jdbc.driver.OracleDriver";
     
     public static Connection getConnection(){
      Connection conn=null;
      if(null==threadLocal.get()){
       try {
        Class.forName(DRIVER);
        conn=DriverManager.getConnection(URL, USER, PWD);
        threadLocal.set(conn);
       } catch (Exception e) {
        e.printStackTrace();
       }
      }else{
       conn=threadLocal.get();
      }
      return conn;
     }
     
     
    }






    2、測試語句

    package com.abin.lee.db.oracle.batch;

    import java.sql.Connection;
    import java.sql.PreparedStatement;
    import java.sql.SQLException;
    import java.text.SimpleDateFormat;

    import junit.framework.TestCase;

    public class OracleBatch extends TestCase {
     public void testinsert() throws SQLException {
      Connection conn = null;
      PreparedStatement ps = null;
      conn = OracleConnection.getConnection();
      String sql = "insert into abing(id,name) values (?,?)";
      ps = conn.prepareStatement(sql);
      System.out.println("start="
        + new SimpleDateFormat("yyyy-MM-dd HH:mm:ss:SSS")
          .format(new java.util.Date()));
      try {
       for (int i = 0; i <= 50000; i++) {
        ps.setObject(1, i);
        ps.setObject(2, "abin" + i);
        ps.addBatch();
        if (i % 10000 == 0) {
         // System.out.println("i="+i);
         ps.executeBatch();
         ps.clearBatch();
        }

       }

      } catch (SQLException e) {
       e.printStackTrace();
      }
      System.out.println("end="
        + new SimpleDateFormat("yyyy-MM-dd HH:mm:ss:SSS")
          .format(new java.util.Date()));

     }

    }

    posted @ 2012-09-17 23:15 abin 閱讀(368) | 評論 (0)編輯 收藏

    1、建表
    create table abing(
    id int not null auto_increment,
    name varchar(30),
    constraint pk primary key(id)
    )

    2.創建函數
    create function fabin(parameter varchar(10))returns char(100)
    BEGIN
    declare result int;
    declare restatus char(100);
    select count(*) into result from abing where name like CONCAT('%',parameter,'%');
    set restatus=CAST(result AS CHAR);
    return(restatus);
    end

    3、測試函數語句
    select fabin('abing');


    posted @ 2012-09-17 22:32 abin 閱讀(439) | 評論 (0)編輯 收藏

    僅列出標題
    共50頁: First 上一頁 26 27 28 29 30 31 32 33 34 下一頁 Last 
    主站蜘蛛池模板: 精品剧情v国产在免费线观看| 2020亚洲男人天堂精品| 麻豆精品国产免费观看| 亚洲黄色免费网站| APP在线免费观看视频| 日韩一区二区三区免费播放| 亚洲美国产亚洲AV| 亚洲看片无码在线视频 | 男男黄GAY片免费网站WWW| 亚洲日韩乱码久久久久久| 亚洲va无码专区国产乱码| 免费a级毛片18以上观看精品| 日韩吃奶摸下AA片免费观看| 四虎精品视频在线永久免费观看| 在线看片免费人成视频福利| 亚洲日韩在线观看免费视频| 黄色a三级免费看| 猫咪免费人成网站在线观看入口| 亚洲国产欧美一区二区三区| 亚洲中文字幕无码中文| 亚洲久悠悠色悠在线播放| 亚洲一区二区三区高清视频| 亚洲成av人片不卡无码| 久久综合亚洲色HEZYO社区| 亚洲第一精品福利| 久久久久亚洲AV成人无码网站| 久久久久久久综合日本亚洲| 久久亚洲精品视频| 久久久亚洲精品国产| 亚洲色图国产精品| 久久亚洲AV成人无码软件| 亚洲精品欧洲精品| 亚洲av成人综合网| 亚洲精品理论电影在线观看| 亚洲AV无码男人的天堂| 日本黄页网址在线看免费不卡| 欧亚一级毛片免费看| 好吊色永久免费视频大全| 怡红院免费的全部视频| 99久久精品国产免费| 亚洲三级高清免费|