HttpComponent 完全解析之獲取HttpClient

  在Java Web中,我們一般使用HttpComponent發起網絡請求。HttpComponent獲取分爲兩步:

   1、獲取到HttpClient

   2、發起請求

  今天來看一下如何配置HttpClient來達到我們想要的效果

一、連接池與設置HttpClient連接池數

    HTTPComponent中有連接池的概念,比如我們有一個連接 連接了www.baidu.com ,那麼當這個連接使用完畢後,下一個線程想要請求 www.baidu.com ,就可以直接使用這個連接,這是連接池的概念,那麼我們如何去設置連接池的大小呢?
  HTTPComponent中有兩個連接管理器,一個是 BasicHttpClientConnectionManager ,一個是PoolingHttpClientConnectionManager。 BasicHttpClientConnectionManager  同一時間只能有一個連接,所以我們基本上不用,而PoolingHttpClientConnectionManager則爲幾乎所有人使用的連接管理器,也就是我們所說的連接池。
  設置poolSize:

          PoolingHttpClientConnectionManager poolingHttpClientConnectionManager = new PoolingHttpClientConnectionManager();
        // MaxPerRoute 設置一路有多大的緩存,比如訪問 www.baidu.com 的爲一路,那麼訪問 www.baidu.com 的連接最大限制到多少,比如是100,那麼最多限制100個連接  www.baidu.com 的
        poolingHttpClientConnectionManager.setDefaultMaxPerRoute(100);
        // 最多對外多少個連接,比如爲 200 ,則爲最大對外200個連接
        poolingHttpClientConnectionManager.setMaxTotal(200); 


  注意連接不像連接數據庫那樣永遠只有一種連接,HttpComponent中不同的域名是不同路的連接,連接成功後不能共用,所以 setDefaultMaxPerRoute 是設置相同路的最大連接數,setMaxTotal是設置最大的所有連接數。

 

二、如何設置默認的 connectionRequestTimeOut、connectionTimeOut、readTimeOut?

          RequestConfig requestConfig = RequestConfig.custom().
                setConnectionRequestTimeout(1000).
                setConnectTimeout(1000).
                setSocketTimeout(5000)
                .build();

  上述爲設置超時時間,其中

   1、connectionRequestTimeOut 爲獲取到 連接請求 的超時時間(也就是說獲取到了連接請求 之後才能進行連接,否則需要等待 )。

   2、ConnectTimeout 爲連接的超時時間。

   3、SocketTimeout爲連接成功後 客戶端和服務進行數據交互的超時時間,是指兩者之間如果兩個數據包之間的時間大於該時間則認爲超時,而不是整個交互的整體時間,比如如果設置1秒超時,如果每隔0.8秒傳輸一次數據,傳輸10次,總共8秒,這樣是不超時的。而如果任意兩個數據包之間的時間超過了1秒,則超時。要注意SocketTimeout不是總時長,不過一般來說,我們經常會阻塞在服務端的處理過程中,服務端的返回一般在一個數據包內,就算是多個數據包,多個數據包發送也很快,所以SocketTimeOut一般可以看成是總時長。

  上述爲設置默認的超時時間,下節會講到設置單次請求的超時時間。

 

三、設置ConnectionSocketFactory

  PoolingHttpClientConnectionManager 爲 連接請求 管理器,當獲取到 連接請求 後,若此 連接請求 未與服務端連接,我們還需要進行連接,此時就用到了 ConnectionSocketFactory 。需要注意的是,HttpComponent中,HTTP的連接類默認只有一個 ,爲 PlainConnectionSocketFactory ,HTTPS的連接類默認也只有一個,爲 SSLConnectionSocketFactory 。

  之所以要知道上述概念,是因爲當我們發起https請求時,若對方服務端爲自籤的證書,則會報x509錯誤,一般情況下,我們會忽略這個錯誤,下面獲取HttpClient的代碼中講到了如何忽略這個錯誤:

        SSLContext sc = null;
        try {
            sc = SSLContext.getInstance("SSLv3");
        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
        }
        // 實現一個X509TrustManager接口,用於繞過驗證,不用修改裏面的方法
        X509TrustManager trustManager = new X509TrustManager() {
            @Override
            public void checkClientTrusted(
                    java.security.cert.X509Certificate[] paramArrayOfX509Certificate,
                    String paramString) {
            }

            @Override
            public void checkServerTrusted(
                    java.security.cert.X509Certificate[] paramArrayOfX509Certificate,
                    String paramString) {
            }

            @Override
            public java.security.cert.X509Certificate[] getAcceptedIssuers() {
                return null;
            }
        };
        try {
            sc.init(null, new TrustManager[]{trustManager}, null);
        } catch (KeyManagementException e) {
            e.printStackTrace();
        }
        // 設置協議http和https對應的處理socket鏈接工廠的對象
        Registry<ConnectionSocketFactory> socketFactoryRegistry = RegistryBuilder.<ConnectionSocketFactory>create()
                .register("http", PlainConnectionSocketFactory.INSTANCE)
                .register("https", new SSLConnectionSocketFactory(sc))
                .build();

 

四、獲取到HttpClient:

  此爲獲取到HttpClient的正確姿勢:

    public static CloseableHttpClient getHttpClient() {

        SSLContext sc = null;
        try {
            sc = SSLContext.getInstance("SSLv3");
        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
        }
        // 實現一個X509TrustManager接口,用於繞過驗證,不用修改裏面的方法
        X509TrustManager trustManager = new X509TrustManager() {
            @Override
            public void checkClientTrusted(
                    java.security.cert.X509Certificate[] paramArrayOfX509Certificate,
                    String paramString) {
            }

            @Override
            public void checkServerTrusted(
                    java.security.cert.X509Certificate[] paramArrayOfX509Certificate,
                    String paramString) {
            }

            @Override
            public java.security.cert.X509Certificate[] getAcceptedIssuers() {
                return null;
            }
        };
        try {
            sc.init(null, new TrustManager[]{trustManager}, null);
        } catch (KeyManagementException e) {
            e.printStackTrace();
        }
        // 設置協議http和https對應的處理socket鏈接工廠的對象
        Registry<ConnectionSocketFactory> socketFactoryRegistry = RegistryBuilder.<ConnectionSocketFactory>create()
                .register("http", PlainConnectionSocketFactory.INSTANCE)
                .register("https", new SSLConnectionSocketFactory(sc))
                .build();

       	// 生成一個PoolingHttpClientConnectionManager
        PoolingHttpClientConnectionManager poolingHttpClientConnectionManager = new PoolingHttpClientConnectionManager(socketFactoryRegistry);
        //  MaxPerRoute 設置一路有多大的緩存,比如訪問 www.baidu.com 的爲一路,那麼訪問 www.baidu.com 的連接最大限制到多少,比如是100,那麼限制最多有100個 www.baidu.com 的連接
        poolingHttpClientConnectionManager.setDefaultMaxPerRoute(100);
        // 最多對外多少個連接,比如爲 200 ,則爲最大對外200個連接
        poolingHttpClientConnectionManager.setMaxTotal(200);

        // 設置超時時間
        RequestConfig requestConfig = RequestConfig.custom().
                setConnectionRequestTimeout(1000).
                setConnectTimeout(1000).
                setSocketTimeout(5000)
                .build();
        CloseableHttpClient httpClient =  HttpClientBuilder.create()
                // 設置默認的config,如果請求沒有設置config的話,那麼就用這個config
                .setDefaultRequestConfig(requestConfig)
                .setConnectionManager(poolingHttpClientConnectionManager)
                .build();

        return httpClient;
    }

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章