HTTP協(xié)議客戶端之HttpClient的基本使用

HttpClient的基本使用

概述

HttpClient 是Apache Jakarta Common 下的子項目铡羡,可以用來提供高效的班利、最新的陈症、功能豐富的支持 HTTP 協(xié)議的客戶端編程工具包,并且它支持 HTTP 協(xié)議最新的版本和建議捺疼。

HttpClient相比JDK自帶的URLConnection外里,增加了易用性和靈活性怎爵,使客戶端發(fā)送Http請求變得更加容易,而且也方便開發(fā)測試接口盅蝗,大大提高開發(fā)的效率鳖链。

常用HTTP協(xié)議客戶端包括有:httpclient、restTemplate墩莫、okHttp

官網(wǎng):https://hc.apache.org/index.html

添加依賴

 <dependency>
     <groupId>org.apache.httpcomponents</groupId>
     <artifactId>httpclient</artifactId>
     <version>4.5.13</version>
 </dependency>

Get請求

1.無參數(shù)的GET請求

    @Test
    public void get() throws IOException {
        // 創(chuàng)建HttpClient對象
        CloseableHttpClient httpClient = HttpClients.createDefault();
        // 創(chuàng)建HttpGet請求
        HttpGet httpGet = new HttpGet("https://www.baidu.com");
        // 響應(yīng)對象
        CloseableHttpResponse response = null;
        try {
            // 使用HttpClient發(fā)起請求
            response = httpClient.execute(httpGet);
            // 判斷響應(yīng)狀態(tài)碼是否為200
            if (response.getStatusLine().getStatusCode() == 200) {
                // 獲取返回數(shù)據(jù)
                HttpEntity httpEntity = response.getEntity();
                String content = EntityUtils.toString(httpEntity, "UTF-8");
                // 打印數(shù)據(jù)長度
                log.info("content:{}", content);
            }
        } finally {
            // 釋放連接
            if (response != null) {
                response.close();
            }
            httpClient.close();
        }
    }

2.帶參數(shù)的GET請求

HttpGet httpGet = new HttpGet("https://www.baidu.com/s?wd=java");

POST請求

1.無參數(shù)的POST請求

    @Test
    public void post() throws IOException {
        // 創(chuàng)建HttpClient對象
        CloseableHttpClient httpClient = HttpClients.createDefault();
        // 創(chuàng)建HttpGet請求
        HttpPost httpPost = new HttpPost("http://www.baidu.com");
        // 響應(yīng)對象
        CloseableHttpResponse response = null;
        try {
            // 使用HttpClient發(fā)起請求
            response = httpClient.execute(httpPost);
            // 判斷響應(yīng)狀態(tài)碼是否為200
            if (response.getStatusLine().getStatusCode() == 200) {
                // 獲取返回數(shù)據(jù)
                HttpEntity httpEntity = response.getEntity();
                String content = EntityUtils.toString(httpEntity, "UTF-8");
                // 打印數(shù)據(jù)長度
                log.info("content:{}", content);
            }
        } finally {
            // 釋放連接
            if (response != null) {
                response.close();
            }
            httpClient.close();
        }
    }

2.帶參數(shù)的POST請求

    public static void main(String[] args) throws Exception {
        // 創(chuàng)建HttpClient對象
        CloseableHttpClient httpClient = HttpClients.createDefault();
        // 創(chuàng)建HttpPost對象芙委,設(shè)置url訪問地址
        HttpPost httpPost = new HttpPost("https://fanyi.baidu.com/langdetect");

        // 聲明List集合,封裝表單中的參數(shù)
        List<NameValuePair> params = new ArrayList<NameValuePair>();
        // 實際請求地址:https://fanyi.baidu.com/langdetect?query=Java
        params.add(new BasicNameValuePair("query", "Java"));

        // 創(chuàng)建表單的Entity對象,第一個參數(shù)是封裝好的表單數(shù)據(jù)狂秦,第二個參數(shù)是編碼
        UrlEncodedFormEntity formEntity = new UrlEncodedFormEntity(params, "utf8");
        //設(shè)置表單的Entity對象到Post請求中
        httpPost.setEntity(formEntity);

        CloseableHttpResponse response = null;
        try {
            // 使用HttpClient發(fā)起請求灌侣,獲取response
            response = httpClient.execute(httpPost);
            // 解析響應(yīng)
            if (response.getStatusLine().getStatusCode() == 200) {
                String content = EntityUtils.toString(response.getEntity(), "utf8");
                log.info("content={}", content);
            }
        } finally {
            // 關(guān)閉資源
            response.close();
            httpClient.close();
        }
    }

連接池

每次請求都要創(chuàng)建HttpClient,會有頻繁創(chuàng)建和銷毀的問題故痊,可以使用連接池來解決這個問題顶瞳。

public class HttpClientPool {

    public static PoolingHttpClientConnectionManager getHttpClientPool(){
        // 創(chuàng)建連接池管理器
        PoolingHttpClientConnectionManager poolingHttpClientConnectionManager = new PoolingHttpClientConnectionManager();
        // 設(shè)置最大連接數(shù)
        poolingHttpClientConnectionManager.setMaxTotal(100);
        // 設(shè)置每個主機的最大連接數(shù)
        poolingHttpClientConnectionManager.setDefaultMaxPerRoute(10);
        return poolingHttpClientConnectionManager;
    }

    public static void main(String[] args) {
        // 使用連接池管理器發(fā)起請求
        PoolingHttpClientConnectionManager httpClientPool = HttpClientPool.getHttpClientPool();
        // 從連接池中獲取HttpClient對象
        CloseableHttpClient httpClient = HttpClients.custom().setConnectionManager(httpClientPool).build();
    }
}

請求參數(shù)配置

對請求進行參數(shù)配置玖姑,如cookie設(shè)置愕秫,代理設(shè)置,以及常用的請求超時時間設(shè)置焰络。

public class HttpClientPool {

    public static PoolingHttpClientConnectionManager getHttpClientPool() {
        // 創(chuàng)建連接池管理器
        PoolingHttpClientConnectionManager poolingHttpClientConnectionManager = new PoolingHttpClientConnectionManager();
        // 設(shè)置最大連接數(shù)
        poolingHttpClientConnectionManager.setMaxTotal(100);
        // 設(shè)置每個主機的最大連接數(shù)
        poolingHttpClientConnectionManager.setDefaultMaxPerRoute(10);
        return poolingHttpClientConnectionManager;
    }

    public static void main(String[] args) throws IOException {
        // 使用連接池管理器發(fā)起請求
        PoolingHttpClientConnectionManager httpClientPool = HttpClientPool.getHttpClientPool();
        // 從連接池中獲取HttpClient對象
        CloseableHttpClient httpClient = HttpClients.custom().setConnectionManager(httpClientPool).build();

        HttpGet httpGet = new HttpGet("http://www.baidu.com");
        // 配置請求信息
        RequestConfig config = RequestConfig.custom()
                // 創(chuàng)建連接的最長時間戴甩,單位是毫秒
                .setConnectTimeout(1000)
                // 設(shè)置獲取連接的最長時間,單位是毫秒
                .setConnectionRequestTimeout(500)
                // 設(shè)置數(shù)據(jù)傳輸?shù)淖铋L時間闪彼,單位是毫秒
                .setSocketTimeout(10 * 1000)
                .build();
        // 給請求設(shè)置請求信息
        httpGet.setConfig(config);

        // 使用HttpClient發(fā)起請求甜孤,獲取response
        CloseableHttpResponse execute = httpClient.execute(httpGet);
    }
}

工具類封裝

HttpClientResult

/**
 * Description: 封裝httpClient響應(yīng)結(jié)果
 */

@Data
@AllArgsConstructor
@NoArgsConstructor
public class HttpClientResult implements Serializable {

    /**
     * 響應(yīng)狀態(tài)碼
     */
    private int code;

    /**
     * 響應(yīng)數(shù)據(jù)
     */
    private String content;
}

HttpClientUtils

import org.apache.http.HttpStatus;
import org.apache.http.NameValuePair;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.*;
import org.apache.http.client.utils.URIBuilder;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.util.EntityUtils;

import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.util.*;

/**
 * Description: httpClient工具類
 */
public class HttpClientUtils {

    // 編碼格式榨汤。發(fā)送編碼格式統(tǒng)一用UTF-8
    private static final String ENCODING = "UTF-8";

    // 設(shè)置連接超時時間者祖,單位毫秒。
    private static final int CONNECT_TIMEOUT = 6000;

    // 請求獲取數(shù)據(jù)的超時時間(即響應(yīng)時間)额湘,單位毫秒描馅。
    private static final int SOCKET_TIMEOUT = 6000;

    /**
     * 發(fā)送get請求把夸;不帶請求頭和請求參數(shù)
     *
     * @param url 請求地址
     */
    public static HttpClientResult doGet(String url) throws Exception {
        return doGet(url, null, null);
    }

    /**
     * 發(fā)送get請求;帶請求參數(shù)
     *
     * @param url    請求地址
     * @param params 請求參數(shù)集合
     */
    public static HttpClientResult doGet(String url, Map<String, String> params) throws Exception {
        return doGet(url, null, params);
    }

    /**
     * 發(fā)送get請求铭污;帶請求頭和請求參數(shù)
     *
     * @param url     請求地址
     * @param headers 請求頭集合
     * @param params  請求參數(shù)集合
     */
    public static HttpClientResult doGet(String url, Map<String, String> headers, Map<String, String> params) throws Exception {
        // 創(chuàng)建httpClient對象
        CloseableHttpClient httpClient = HttpClients.createDefault();

        // 創(chuàng)建訪問的地址
        URIBuilder uriBuilder = new URIBuilder(url);
        if (params != null) {
            Set<Map.Entry<String, String>> entrySet = params.entrySet();
            for (Map.Entry<String, String> entry : entrySet) {
                uriBuilder.setParameter(entry.getKey(), entry.getValue());
            }
        }

        // 創(chuàng)建http對象
        HttpGet httpGet = new HttpGet(uriBuilder.build());
        /**
         * setConnectTimeout:設(shè)置連接超時時間恋日,單位毫秒膀篮。
         * setConnectionRequestTimeout:設(shè)置從connect Manager(連接池)獲取Connection
         * 超時時間,單位毫秒岂膳。這個屬性是新加的屬性誓竿,因為目前版本是可以共享連接池的。
         * setSocketTimeout:請求獲取數(shù)據(jù)的超時時間(即響應(yīng)時間)谈截,單位毫秒筷屡。 如果訪問一個接口,多少時間內(nèi)無法返回數(shù)據(jù)傻盟,就直接放棄此次調(diào)用速蕊。
         */
        RequestConfig requestConfig = RequestConfig.custom().setConnectTimeout(CONNECT_TIMEOUT).setSocketTimeout(SOCKET_TIMEOUT).build();
        httpGet.setConfig(requestConfig);

        // 設(shè)置請求頭
        packageHeader(headers, httpGet);

        try {
            // 執(zhí)行請求并獲得響應(yīng)結(jié)果
            return getHttpClientResult(httpClient, httpGet);
        } finally {
            // 釋放資源
            close(httpClient);
        }
    }

    /**
     * 發(fā)送post請求;不帶請求頭和請求參數(shù)
     *
     * @param url 請求地址
     */
    public static HttpClientResult doPost(String url) throws Exception {
        return doPost(url, null, null);
    }

    /**
     * 發(fā)送post請求娘赴;帶請求參數(shù)
     *
     * @param url    請求地址
     * @param params 參數(shù)集合
     */
    public static HttpClientResult doPost(String url, Map<String, String> params) throws Exception {
        return doPost(url, null, params);
    }

    /**
     * 發(fā)送post請求规哲;帶請求頭和請求參數(shù)
     *
     * @param url     請求地址
     * @param headers 請求頭集合
     * @param params  請求參數(shù)集合
     */
    public static HttpClientResult doPost(String url, Map<String, String> headers, Map<String, String> params) throws Exception {
        // 創(chuàng)建httpClient對象
        CloseableHttpClient httpClient = HttpClients.createDefault();

        // 創(chuàng)建http對象
        HttpPost httpPost = new HttpPost(url);
        /**
         * setConnectTimeout:設(shè)置連接超時時間,單位毫秒诽表。
         * setConnectionRequestTimeout:設(shè)置從connect Manager(連接池)獲取Connection
         * 超時時間唉锌,單位毫秒。這個屬性是新加的屬性竿奏,因為目前版本是可以共享連接池的袄简。
         * setSocketTimeout:請求獲取數(shù)據(jù)的超時時間(即響應(yīng)時間),單位毫秒泛啸。 如果訪問一個接口绿语,多少時間內(nèi)無法返回數(shù)據(jù),就直接放棄此次調(diào)用候址。
         */
        RequestConfig requestConfig = RequestConfig.custom().setConnectTimeout(CONNECT_TIMEOUT).setSocketTimeout(SOCKET_TIMEOUT).build();
        httpPost.setConfig(requestConfig);
        // 設(shè)置請求頭
        /*httpPost.setHeader("Cookie", "");
        httpPost.setHeader("Accept", "application/json");
        httpPost.setHeader("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/105.0.0.0 Safari/537.36");*/
        packageHeader(headers, httpPost);

        // 封裝請求參數(shù)
        packageParam(params, httpPost);

        try {
            // 執(zhí)行請求并獲得響應(yīng)結(jié)果
            return getHttpClientResult(httpClient, httpPost);
        } finally {
            // 釋放資源
            close(httpClient);
        }
    }

    /**
     * 發(fā)送put請求吕粹;不帶請求參數(shù)
     *
     * @param url 請求地址
     */
    public static HttpClientResult doPut(String url) throws Exception {
        return doPut(url, null);
    }

    /**
     * 發(fā)送put請求;帶請求參數(shù)
     *
     * @param url    請求地址
     * @param params 參數(shù)集合
     */
    public static HttpClientResult doPut(String url, Map<String, String> params) throws Exception {
        CloseableHttpClient httpClient = HttpClients.createDefault();
        HttpPut httpPut = new HttpPut(url);
        RequestConfig requestConfig = RequestConfig.custom().setConnectTimeout(CONNECT_TIMEOUT).setSocketTimeout(SOCKET_TIMEOUT).build();
        httpPut.setConfig(requestConfig);

        packageParam(params, httpPut);

        try {
            return getHttpClientResult(httpClient, httpPut);
        } finally {
            close(httpClient);
        }
    }

    /**
     * 發(fā)送delete請求岗仑;不帶請求參數(shù)
     *
     * @param url 請求地址
     */
    public static HttpClientResult doDelete(String url) throws Exception {
        CloseableHttpClient httpClient = HttpClients.createDefault();
        HttpDelete httpDelete = new HttpDelete(url);
        RequestConfig requestConfig = RequestConfig.custom().setConnectTimeout(CONNECT_TIMEOUT).setSocketTimeout(SOCKET_TIMEOUT).build();
        httpDelete.setConfig(requestConfig);

        try {
            return getHttpClientResult(httpClient, httpDelete);
        } finally {
            close(httpClient);
        }
    }

    /**
     * 發(fā)送delete請求匹耕;帶請求參數(shù)
     *
     * @param url    請求地址
     * @param params 參數(shù)集合
     */
    public static HttpClientResult doDelete(String url, Map<String, String> params) throws Exception {
        if (params == null) {
            params = new HashMap<>();
        }

        params.put("_method", "delete");
        return doPost(url, params);
    }

    /**
     * Description: 封裝請求頭
     */
    public static void packageHeader(Map<String, String> params, HttpRequestBase httpMethod) {
        // 封裝請求頭
        if (params != null) {
            Set<Map.Entry<String, String>> entrySet = params.entrySet();
            for (Map.Entry<String, String> entry : entrySet) {
                // 設(shè)置到請求頭到HttpRequestBase對象中
                httpMethod.setHeader(entry.getKey(), entry.getValue());
            }
        }
    }

    /**
     * Description: 封裝請求參數(shù)
     */
    public static void packageParam(Map<String, String> params, HttpEntityEnclosingRequestBase httpMethod)
            throws UnsupportedEncodingException {
        // 封裝請求參數(shù)
        if (params != null) {
            List<NameValuePair> nvps = new ArrayList<>();
            Set<Map.Entry<String, String>> entrySet = params.entrySet();
            for (Map.Entry<String, String> entry : entrySet) {
                nvps.add(new BasicNameValuePair(entry.getKey(), entry.getValue()));
            }

            // 設(shè)置到請求的http對象中
            httpMethod.setEntity(new UrlEncodedFormEntity(nvps, ENCODING));
        }
    }

    /**
     * Description: 獲得響應(yīng)結(jié)果
     */
    public static HttpClientResult getHttpClientResult(CloseableHttpClient httpClient, HttpRequestBase httpMethod) throws IOException {
        try (CloseableHttpResponse httpResponse = httpClient.execute(httpMethod)) {
            // 獲取返回結(jié)果
            if (httpResponse != null && httpResponse.getStatusLine() != null) {
                String content = "";
                if (httpResponse.getEntity() != null) {
                    content = EntityUtils.toString(httpResponse.getEntity(), ENCODING);
                }
                return new HttpClientResult(httpResponse.getStatusLine().getStatusCode(), content);
            }
        }
        return new HttpClientResult(HttpStatus.SC_INTERNAL_SERVER_ERROR, null);
    }

    /**
     * Description: 釋放資源
     */
    public static void close(CloseableHttpClient httpClient) throws IOException {
        if (httpClient != null) {
            httpClient.close();
        }
    }

}


測試

public class HttpClientUtilsTest {

    /**
     * Description: 測試get無參請求
     */
    @Test
    public void testGet() throws Exception {
        HttpClientResult result = HttpClientUtils.doGet("https://www.baidu.com");
        System.out.println(result);
    }

    /**
     * Description: 測試get帶參請求
     */
    @Test
    public void testGetWithParam() throws Exception {
        Map<String, String> params = new HashMap<String, String>();
        params.put("word", "java");
        HttpClientResult result = HttpClientUtils.doGet("url", params);
        System.out.println(result);
    }

    /**
     * Description: 測試post帶請求頭不帶請求參數(shù)
     */
    @Test
    public void testPost() throws Exception {
        Map<String, String> headers = new HashMap<String, String>();
        headers.put("Cookie", "cokie");
        headers.put("Accept", "application/json");
        headers.put("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/105.0.0.0 Safari/537.36");
        HttpClientResult result = HttpClientUtils.doPost("url", headers, null);
        System.out.println(result);
    }

    /**
     * Description: 測試post帶參請求
     */
    @Test
    public void testPostWithParam() throws Exception {
        Map<String, String> params = new HashMap<String, String>();
        params.put("word", "java");
        HttpClientResult result = HttpClientUtils.doPost("url", params);
        System.out.println(result);
    }
}
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市荠雕,隨后出現(xiàn)的幾起案子稳其,更是在濱河造成了極大的恐慌,老刑警劉巖炸卑,帶你破解...
    沈念sama閱讀 206,968評論 6 482
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件既鞠,死亡現(xiàn)場離奇詭異,居然都是意外死亡盖文,警方通過查閱死者的電腦和手機嘱蛋,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,601評論 2 382
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人浑槽,你說我怎么就攤上這事蒋失。” “怎么了桐玻?”我有些...
    開封第一講書人閱讀 153,220評論 0 344
  • 文/不壞的土叔 我叫張陵篙挽,是天一觀的道長。 經(jīng)常有香客問我镊靴,道長铣卡,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 55,416評論 1 279
  • 正文 為了忘掉前任偏竟,我火速辦了婚禮煮落,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘踊谋。我一直安慰自己蝉仇,他們只是感情好,可當(dāng)我...
    茶點故事閱讀 64,425評論 5 374
  • 文/花漫 我一把揭開白布殖蚕。 她就那樣靜靜地躺著轿衔,像睡著了一般。 火紅的嫁衣襯著肌膚如雪睦疫。 梳的紋絲不亂的頭發(fā)上害驹,一...
    開封第一講書人閱讀 49,144評論 1 285
  • 那天,我揣著相機與錄音蛤育,去河邊找鬼宛官。 笑死,一個胖子當(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
  • 正文 獨居荒郊野嶺守林人離奇死亡扳剿,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,028評論 2 325
  • 正文 我和宋清朗相戀三年旁趟,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片庇绽。...
    茶點故事閱讀 38,137評論 1 334
  • 序言:一個原本活蹦亂跳的男人離奇死亡锡搜,死狀恐怖橙困,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情耕餐,我是刑警寧澤凡傅,帶...
    沈念sama閱讀 33,783評論 4 324
  • 正文 年R本政府宣布,位于F島的核電站肠缔,受9級特大地震影響夏跷,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜明未,卻給世界環(huán)境...
    茶點故事閱讀 39,343評論 3 307
  • 文/蒙蒙 一槽华、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧趟妥,春花似錦猫态、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,333評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至行疏,卻和暖如春匆光,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背酿联。 一陣腳步聲響...
    開封第一講書人閱讀 31,559評論 1 262
  • 我被黑心中介騙來泰國打工终息, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人贞让。 一個月前我還...
    沈念sama閱讀 45,595評論 2 355
  • 正文 我出身青樓周崭,卻偏偏與公主長得像,于是被迫代替她去往敵國和親喳张。 傳聞我的和親對象是個殘疾皇子续镇,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 42,901評論 2 345

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