HttpClient 4.5.2-(四)連接超時的配置

緊接上一節(jié)匆笤,本節(jié)記錄 【連接超時的配置】
  工作中有這樣一個需求净薛,要對上千臺的服務(wù)器進(jìn)行更新測試矢劲,這是需要開幾百個線程做并發(fā)測試,每個線程中都有N次的Http請求甸各,看服務(wù)器是否可以頂?shù)米?/code>垛贤。但是碰到一個問題,那就是訪問的過程中有些線程莫名其妙就不訪問了趣倾,觀察服務(wù)器端聘惦,并沒有請求進(jìn)來。開始各種懷疑儒恋,是線程自己死掉了善绎?還是Windows對每個進(jìn)程有線程的限制?亦或者是HttpClient對總連接數(shù)量有限制诫尽?
  最后經(jīng)過每一步的測試和排查禀酱,確定問題在于兩方面:

  1. httpClient客戶端連接對象并沒有配置連接池,使用默認(rèn)的連接池不能支持那么多的并發(fā)量牧嫉。
  2. 沒有給每一次的連接設(shè)置超時時間獲取連接超時 請求超時 響應(yīng)超時剂跟,如果沒有設(shè)置超時時間,連接可能會一直存在阻塞酣藻,所以線程一直停在那里曹洽,其實(shí)線程并沒有死掉
也就是說辽剧,我們只需把上述兩個問題解決問題就迎刃而解了送淆。本節(jié)先說連接超時時間的設(shè)置。

上代碼:
package com.lynchj.writing;

/**
 * Http請求工具類
 * 
 * @author 大漠知秋
 */
public class HttpRequestUtils {
    
}
  • 獲取帶超時間的httpClient客戶端連接對象
/**
 * 獲取Http客戶端連接對象
 * 
 * @param timeOut 超時時間
 * @return Http客戶端連接對象
 */
public static HttpClient getHttpClient(Integer timeOut) {
    // 創(chuàng)建Http請求配置參數(shù)
    RequestConfig requestConfig = RequestConfig.custom()
        // 獲取連接超時時間
        .setConnectionRequestTimeout(timeOut)
        // 請求超時時間
        .setConnectTimeout(timeOut)
        // 響應(yīng)超時時間
        .setSocketTimeout(timeOut)
        .build();
    
    // 創(chuàng)建httpClient
    return HttpClients.custom().setDefaultRequestConfig(requestConfig).build();
}
  • POST請求方法
/**
 * GET請求
 * 
 * @param url 請求地址
 * @param timeOut 超時時間
 * @return
 */
public static String httpGet(String url, Integer timeOut) {
    String msg = "-1";
    
    // 獲取客戶端連接對象
    CloseableHttpClient httpClient = getHttpClient(timeOut);
    // 創(chuàng)建GET請求對象
    HttpGet httpGet = new HttpGet(url);
    
    CloseableHttpResponse response = null;
    
    try {
        // 執(zhí)行請求
        response = httpClient.execute(httpGet);
        // 獲取響應(yīng)實(shí)體
        HttpEntity entity = response.getEntity();
        // 獲取響應(yīng)信息
        msg = EntityUtils.toString(entity, "UTF-8");
    } catch (ClientProtocolException e) {
        System.err.println("協(xié)議錯誤");
        e.printStackTrace();
    } catch (ParseException e) {
        System.err.println("解析錯誤");
        e.printStackTrace();
    } catch (IOException e) {
        System.err.println("IO錯誤");
        e.printStackTrace();
    } finally {
        if (null != response) {
            try {
                response.close();
            } catch (IOException e) {
                System.err.println("釋放鏈接錯誤");
                e.printStackTrace();
            }
        }
    }
    
    return msg;
}
  • 測試main方法
public static void main(String[] args) {
        
    System.out.println(httpGet("http://www.baidu.com", 6000));
    
}

經(jīng)多次測試結(jié)果抖仅,發(fā)現(xiàn)如果僅僅這是這么配置的話坊夫,還是會存在設(shè)置超時時間不起作用的情況砖第,最后排查結(jié)果

  • 經(jīng)過修改后的獲取客戶端連接工具的方法
/**
 * 獲取Http客戶端連接對象
 * 
 * @param timeOut 超時時間
 * @return Http客戶端連接對象
 */
public static CloseableHttpClient getHttpClient(Integer timeOut) {
    // 創(chuàng)建Http請求配置參數(shù)
    RequestConfig requestConfig = RequestConfig.custom()
        // 獲取連接超時時間
        .setConnectionRequestTimeout(timeOut)
        // 請求超時時間
        .setConnectTimeout(timeOut)
        // 響應(yīng)超時時間
        .setSocketTimeout(timeOut)
        .build();
    
    /**
     * 測出超時重試機(jī)制為了防止超時不生效而設(shè)置
     *  如果直接放回false,不重試
     *  這里會根據(jù)情況進(jìn)行判斷是否重試
     */
    HttpRequestRetryHandler retry = new HttpRequestRetryHandler() {
        @Override
        public boolean retryRequest(IOException exception, int executionCount, HttpContext context) {
            if (executionCount >= 3) {// 如果已經(jīng)重試了3次,就放棄
                return false;
            }
            if (exception instanceof NoHttpResponseException) {// 如果服務(wù)器丟掉了連接环凿,那么就重試
                return true;
            }
            if (exception instanceof SSLHandshakeException) {// 不要重試SSL握手異常
                return false;
            }
            if (exception instanceof InterruptedIOException) {// 超時
                return true;
            }
            if (exception instanceof UnknownHostException) {// 目標(biāo)服務(wù)器不可達(dá)
                return false;
            }
            if (exception instanceof ConnectTimeoutException) {// 連接被拒絕
                return false;
            }
            if (exception instanceof SSLException) {// ssl握手異常
                return false;
            }
            HttpClientContext clientContext = HttpClientContext.adapt(context);
            HttpRequest request = clientContext.getRequest();
            // 如果請求是冪等的梧兼,就再次嘗試
            if (!(request instanceof HttpEntityEnclosingRequest)) {
                return true;
            }
            return false;
        }
    };
    
    // 創(chuàng)建httpClient
    return HttpClients.custom()
            // 把請求相關(guān)的超時信息設(shè)置到連接客戶端
            .setDefaultRequestConfig(requestConfig)
            // 把請求重試設(shè)置到連接客戶端
            .setRetryHandler(retry)
            .build();
}
  • 最后完整代碼
package com.lynchj.writing;

import java.io.IOException;
import java.io.InterruptedIOException;
import java.net.UnknownHostException;

import javax.net.ssl.SSLException;
import javax.net.ssl.SSLHandshakeException;

import org.apache.http.HttpEntity;
import org.apache.http.HttpEntityEnclosingRequest;
import org.apache.http.HttpRequest;
import org.apache.http.NoHttpResponseException;
import org.apache.http.ParseException;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.HttpRequestRetryHandler;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.protocol.HttpClientContext;
import org.apache.http.conn.ConnectTimeoutException;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.protocol.HttpContext;
import org.apache.http.util.EntityUtils;

/**
 * Http請求工具類
 * 
 * @author 大漠知秋
 */
public class HttpRequestUtils {
    
    /**
     * 獲取Http客戶端連接對象
     * 
     * @param timeOut 超時時間
     * @return Http客戶端連接對象
     */
    public static CloseableHttpClient getHttpClient(Integer timeOut) {
        // 創(chuàng)建Http請求配置參數(shù)
        RequestConfig requestConfig = RequestConfig.custom()
            // 獲取連接超時時間
            .setConnectionRequestTimeout(timeOut)
            // 請求超時時間
            .setConnectTimeout(timeOut)
            // 響應(yīng)超時時間
            .setSocketTimeout(timeOut)
            .build();
        
        /**
         * 測出超時重試機(jī)制為了防止超時不生效而設(shè)置
         *  如果直接放回false,不重試
         *  這里會根據(jù)情況進(jìn)行判斷是否重試
         */
        HttpRequestRetryHandler retry = new HttpRequestRetryHandler() {
            @Override
            public boolean retryRequest(IOException exception, int executionCount, HttpContext context) {
                if (executionCount >= 3) {// 如果已經(jīng)重試了3次,就放棄
                    return false;
                }
                if (exception instanceof NoHttpResponseException) {// 如果服務(wù)器丟掉了連接智听,那么就重試
                    return true;
                }
                if (exception instanceof SSLHandshakeException) {// 不要重試SSL握手異常
                    return false;
                }
                if (exception instanceof InterruptedIOException) {// 超時
                    return true;
                }
                if (exception instanceof UnknownHostException) {// 目標(biāo)服務(wù)器不可達(dá)
                    return false;
                }
                if (exception instanceof ConnectTimeoutException) {// 連接被拒絕
                    return false;
                }
                if (exception instanceof SSLException) {// ssl握手異常
                    return false;
                }
                HttpClientContext clientContext = HttpClientContext.adapt(context);
                HttpRequest request = clientContext.getRequest();
                // 如果請求是冪等的羽杰,就再次嘗試
                if (!(request instanceof HttpEntityEnclosingRequest)) {
                    return true;
                }
                return false;
            }
        };
        
        // 創(chuàng)建httpClient
        return HttpClients.custom()
                // 把請求相關(guān)的超時信息設(shè)置到連接客戶端
                .setDefaultRequestConfig(requestConfig)
                // 把請求重試設(shè)置到連接客戶端
                .setRetryHandler(retry)
                .build();
    }
    
    /**
     * GET請求
     * 
     * @param url 請求地址
     * @param timeOut 超時時間
     * @return
     */
    public static String httpGet(String url, Integer timeOut) {
        String msg = "-1";
        
        // 獲取客戶端連接對象
        CloseableHttpClient httpClient = getHttpClient(timeOut);
        // 創(chuàng)建GET請求對象
        HttpGet httpGet = new HttpGet(url);
        
        CloseableHttpResponse response = null;
        
        try {
            // 執(zhí)行請求
            response = httpClient.execute(httpGet);
            // 獲取響應(yīng)實(shí)體
            HttpEntity entity = response.getEntity();
            // 獲取響應(yīng)信息
            msg = EntityUtils.toString(entity, "UTF-8");
        } catch (ClientProtocolException e) {
            System.err.println("協(xié)議錯誤");
            e.printStackTrace();
        } catch (ParseException e) {
            System.err.println("解析錯誤");
            e.printStackTrace();
        } catch (IOException e) {
            System.err.println("IO錯誤");
            e.printStackTrace();
        } finally {
            if (null != response) {
                try {
                    EntityUtils.consume(response.getEntity());
                    response.close();
                } catch (IOException e) {
                    System.err.println("釋放鏈接錯誤");
                    e.printStackTrace();
                }
            }
        }
        
        return msg;
    }
    
    public static void main(String[] args) {
        
        System.out.println(httpGet("http://www.baidu.com", 6000));
        
    }
    
}

至此,本節(jié)完畢到推,下一節(jié)記錄【連接池的配置】

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末考赛,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子莉测,更是在濱河造成了極大的恐慌颜骤,老刑警劉巖,帶你破解...
    沈念sama閱讀 206,968評論 6 482
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件捣卤,死亡現(xiàn)場離奇詭異忍抽,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)董朝,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,601評論 2 382
  • 文/潘曉璐 我一進(jìn)店門鸠项,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人子姜,你說我怎么就攤上這事祟绊。” “怎么了哥捕?”我有些...
    開封第一講書人閱讀 153,220評論 0 344
  • 文/不壞的土叔 我叫張陵牧抽,是天一觀的道長。 經(jīng)常有香客問我扭弧,道長阎姥,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 55,416評論 1 279
  • 正文 為了忘掉前任鸽捻,我火速辦了婚禮呼巴,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘御蒲。我一直安慰自己衣赶,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,425評論 5 374
  • 文/花漫 我一把揭開白布厚满。 她就那樣靜靜地躺著府瞄,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上遵馆,一...
    開封第一講書人閱讀 49,144評論 1 285
  • 那天鲸郊,我揣著相機(jī)與錄音,去河邊找鬼货邓。 笑死秆撮,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的换况。 我是一名探鬼主播职辨,決...
    沈念sama閱讀 38,432評論 3 401
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼戈二!你這毒婦竟也來了舒裤?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 37,088評論 0 261
  • 序言:老撾萬榮一對情侶失蹤觉吭,失蹤者是張志新(化名)和其女友劉穎腾供,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體亏栈,經(jīng)...
    沈念sama閱讀 43,586評論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡台腥,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,028評論 2 325
  • 正文 我和宋清朗相戀三年宏赘,在試婚紗的時候發(fā)現(xiàn)自己被綠了绒北。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 38,137評論 1 334
  • 序言:一個原本活蹦亂跳的男人離奇死亡察署,死狀恐怖闷游,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情贴汪,我是刑警寧澤脐往,帶...
    沈念sama閱讀 33,783評論 4 324
  • 正文 年R本政府宣布,位于F島的核電站扳埂,受9級特大地震影響业簿,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜阳懂,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,343評論 3 307
  • 文/蒙蒙 一梅尤、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧岩调,春花似錦巷燥、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,333評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至葱淳,卻和暖如春钝腺,著一層夾襖步出監(jiān)牢的瞬間抛姑,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,559評論 1 262
  • 我被黑心中介騙來泰國打工艳狐, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留途戒,地道東北人。 一個月前我還...
    沈念sama閱讀 45,595評論 2 355
  • 正文 我出身青樓僵驰,卻偏偏與公主長得像喷斋,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子蒜茴,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,901評論 2 345

推薦閱讀更多精彩內(nèi)容

  • Spring Cloud為開發(fā)人員提供了快速構(gòu)建分布式系統(tǒng)中一些常見模式的工具(例如配置管理星爪,服務(wù)發(fā)現(xiàn),斷路器粉私,智...
    卡卡羅2017閱讀 134,601評論 18 139
  • 第一章 Nginx簡介 Nginx是什么 沒有聽過Nginx顽腾?那么一定聽過它的“同行”Apache吧!Ngi...
    JokerW閱讀 32,642評論 24 1,002
  • 本來是個簡單工具的使用诺核,沒必要寫什么博客的抄肖,但是StartUML有幾個地方在畫圖的時候和別的工具(rose)不太一...
    千山萬水迷了鹿閱讀 3,848評論 0 1
  • 《風(fēng)雨中的菊花》閱讀題 風(fēng)雨中的菊花 午后的天灰蒙蒙的,烏云壓得很低窖杀,似乎要下雨漓摩。 多爾先生情緒很低落,他最煩在這...
    躲進(jìn)小樓看燈火閱讀 11,022評論 0 0
  • (寫在感恩節(jié)) 夜晚三點(diǎn)半的鬧鐘響得實(shí)兀 黑夜倦曲在冰涼的馬路 對樓的窗戶閃耀著燈光 誰家嬰孩半夜啼哭 星星眨著節(jié)...
    山上人家123閱讀 211評論 5 13