HttpClient 基於連接池的使用


場景:調用外部系統接口的http請求

要求:

     1:可能是http請求,也可能是https請求

     2:需要加入連接池的概念,不能每次發起請求都新建一個連接(每次連接握手三次,效率太低)

 

准備使用httpclient 4.5的版本

HTTPClient的特性

  1. 基於標准、純凈的Java語言。實現了Http1.0和Http1.1

  2. 以可擴展的面向對象的結構實現了Http全部的方法(GET, POST, PUT, DELETE, HEAD, OPTIONS, and TRACE)。

  3. 支持HTTPS協議。

  4. 通過Http代理建立透明的連接。

  5. 利用CONNECT方法通過Http代理建立隧道的https連接。

  6. Basic, Digest, NTLMv1, NTLMv2, NTLM2 Session, SNPNEGO/Kerberos認證方案。

  7. 插件式的自定義認證方案。

  8. 便攜可靠的套接字工廠使它更容易的使用第三方解決方案。

  9. 連接管理器支持多線程應用。支持設置最大連接數,同時支持設置每個主機的最大連接數,發現並關閉過期的連接。

  10. 自動處理Set-Cookie中的Cookie。

  11. 插件式的自定義Cookie策略。

  12. Request的輸出流可以避免流中內容直接緩沖到socket服務器。

  13. Response的輸入流可以有效的從socket服務器直接讀取相應內容。

  14. 在http1.0和http1.1中利用KeepAlive保持持久連接。

  15. 直接獲取服務器發送的response code和 headers。

  16. 設置連接超時的能力。

  17. 實驗性的支持http1.1 response caching。

  18. 源代碼基於Apache License 可免費獲取。

 

     在HttpClient 4.x版本中引入了大量的構造器設計模式,很多的配置都不建議直接new出來,而且相關的API也有所改動,例如連接參數,以前是直接new出HttpConnectionParams對象后通過set方法逐一設置屬性,現在有了構造器,可以通過如下方式進行構造:

  1. ConnectionConfig.custom().setCharset(Charsets.toCharset(defaultEncoding)).build();  
  2. SocketConfig.custom().setSoTimeout(100000).build();

    實現訪問自簽名https的要點就是建立一個自定義的SSLContext對象,該對象要有可以存儲信任密鑰的容器,還要有判斷當前連接是否受信任的策略,以及在SSL連接工廠中取消對所有主機名的驗證。他的代碼將會在本文最后貼出來,以下代碼均針對新HttpClient

   首先建立一個信任任何密鑰的策略。代碼很簡單,不去考慮證書鏈和授權類型,均認為是受信任的

  1. class AnyTrustStrategy implements TrustStrategy{  
          
        @Override  
        public boolean isTrusted(X509Certificate[] chain, String authType) throws CertificateException {  
            return true;  
        }  
    }  

     

      HttpClient既能處理常規http協議,又能支持https,根源在於在連接管理器中注冊了不同的連接創建工廠。當訪問url的schema為http時,調用明文連接套節工廠來建立連接;當訪問url的schema為https時,調用SSL連接套接字工廠來建立連接。對於http的連接我們不做修改,只針對使用SSL的https連接來進行自定義:

 

RegistryBuilder<ConnectionSocketFactory> registryBuilder = RegistryBuilder.<ConnectionSocketFactory>create();  
ConnectionSocketFactory plainSF
= new PlainConnectionSocketFactory(); registryBuilder.register("http", plainSF); //指定信任密鑰存儲對象和連接套接字工廠 try { KeyStore trustStore = KeyStore.getInstance(KeyStore.getDefaultType()); SSLContext sslContext = SSLContexts.custom().useTLS().loadTrustMaterial(trustStore, new AnyTrustStrategy()).build(); LayeredConnectionSocketFactory sslSF = new SSLConnectionSocketFactory(sslContext, SSLConnectionSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER); registryBuilder.register("https", sslSF); } catch (KeyStoreException e) { throw new RuntimeException(e); } catch (KeyManagementException e) { throw new RuntimeException(e); } catch (NoSuchAlgorithmException e) { throw new RuntimeException(e); } Registry<ConnectionSocketFactory> registry = registryBuilder.build();

 

      在上述代碼中可以看到,首先建立了一個密鑰存儲容器,隨后讓SSLContext開啟TLS,並將密鑰存儲容器和信任任何主機的策略加載到該上下文中。構造SSL連接工廠時,將自定義的上下文和允許任何主機名通過校驗的指令一並傳入。最后將這樣一個自定義的SSL連接工廠注冊到https協議上。

 

      前期准備已經完成,接下來我們要獲得HttpClient對象:

//設置連接管理器  
PoolingHttpClientConnectionManager connManager = new PoolingHttpClientConnectionManager(registry);  
connManager.setDefaultConnectionConfig(connConfig);  
connManager.setDefaultSocketConfig(socketConfig);  
//構建客戶端  
HttpClient client= HttpClientBuilder.create().setConnectionManager(connManager).build();  

       為了讓我們的HttpClient具有多線程處理的能力,連接管理器選用了PoolingHttpClientConnectionManager,將協議注冊信息傳入連接管理器,最后再次利用構造器的模式創建出我們需要的HttpClient。隨后的GET/POST請求發起方法http和https之間沒有差異。

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM