Apache HttpClient 使用教程 以及 Spring 的 RestTemplate

Apache HttpClient 使用教程 以及 Spring 的 RestTemplate

本文源代碼已經收錄在我的碼云上面的HttpClientDemo 的模塊,大家可以參考 ,地址https://gitee.com/njitzyd/JavaDemoCollection

HttpClient簡介

HttpClient是Apache Jakarta Common下的子項目,用來提供高效的、最新的、功能豐富的支持HTTP協議的客戶端編程工具包,并且它支持HTTP協議最新的版本。我們可以通過HttpClient發送各種HTTP方法。

主要特性

  • 基于標準、純凈的Java語言,實現了HTTP1.0和HTTP1.1。
  • 以可擴展的面向對象的結構實現了HTTP全部的方法(GET, POST, PUT, DELETE, HEAD, OPTIONS, and TRACE)。
  • 支持加密的HTTPS協議(HTTP通過SSL協議)。
  • 通過HTTP代理方式建立透明的連接。
  • 利用CONNECT方法通過HTTP代理建立隧道的HTTPS連接。
  • Basic, Digest, NTLMv1, NTLMv2, NTLM2 Session, SNPNEGO/Kerberos認證方案。
  • 插件式的自定義認證方案。
  • 可插拔的安全套接字工廠,使得接入第三方解決方案變得更容易
  • 連接管理支持使用多線程的的應用。支持設置最大連接數,同時支持設置每個主機的最大連接數,發現并關閉過期的連接。
  • 自動化處理Set-Cookie:來自服務器的頭,并在適當的時候將它們發送回cookie。
  • 可以自定義Cookie策略的插件化機制。
  • Request的輸出流可以避免流中內容體直接從socket緩沖到服務器。
  • Response的輸入流可以有效的從socket服務器直接讀取相應內容。
  • 在HTTP1.0和HTTP1.1中使用用KeepAlive來保持持久連接。
  • 可以直接獲取服務器發送的響應碼和響應頭部。
  • 具備設置連接超時的能力。
  • 支持HTTP/1.1 響應緩存。
  • 源代碼基于Apache License 可免費獲取。

一般使用步驟

使用HttpClient發送請求、接收響應,一般需要以下步驟。
HttpGet請求響應的一般步驟:
1). 創建HttpClient對象,可以使用HttpClients.createDefault();
2). 如果是無參數的GET請求,則直接使用構造方法HttpGet(String url)創建HttpGet對象即可;
如果是帶參數GET請求,則可以先使用URIBuilder(String url)創建對象,再調用addParameter(String param, String value),或setParameter(String param, String value)來設置請求參數,并調用build()方法構建一個URI對象。只有構造方法HttpGet(URI uri)來創建HttpGet對象。
3). 創建HttpResponse,調用HttpClient對象的execute(HttpUriRequest request)發送請求,該方法返回一個HttpResponse。調用HttpResponsegetAllHeaders()、getHeaders(String name)等方法可獲取服務器的響應頭;調用HttpResponsegetEntity()方法可獲取HttpEntity對象,該對象包裝了服務器的響應內容。程序可通過該對象獲取服務器的響應內容。通過調用getStatusLine().getStatusCode()可以獲取響應狀態碼。
4). 釋放連接。

HttpPost請求響應的一般步驟:
1). 創建HttpClient對象,可以使用HttpClients.createDefault()
2). 如果是無參數的GET請求,則直接使用構造方法HttpPost(String url)創建HttpPost對象即可;
如果是帶參數POST請求,先構建HttpEntity對象并設置請求參數,然后調用setEntity(HttpEntity entity)創建HttpPost對象。
3). 創建HttpResponse,調用HttpClient對象的execute(HttpUriRequest request)發送請求,該方法返回一個HttpResponse。調用HttpResponsegetAllHeaders()、getHeaders(String name)等方法可獲取服務器的響應頭;調用HttpResponsegetEntity()方法可獲取HttpEntity對象,該對象包裝了服務器的響應內容。程序可通過該對象獲取服務器的響應內容。通過調用getStatusLine().getStatusCode()可以獲取響應狀態碼。
4). 釋放連接。

使用教程(基于Maven)

  1. 引入依賴
<dependency>
    <groupId>org.apache.httpcomponents</groupId>
    <artifactId>httpclient</artifactId>
    <version>4.5.12</version>
</dependency>

<dependency>
     <groupId>commons-io</groupId>
      <artifactId>commons-io</artifactId>
      <version>2.4</version>
</dependency>

  1. 具體代碼實現

    
    public class HttpClientTest {
    
        /**
         *普通的GET請求
         */
        public static void main(String[] args) throws Exception {
            
            HttpClientTest clientTest = new HttpClientTest();
    //        clientTest.doGet();
    
    //        clientTest.doGETParam();
            clientTest.doPOST();
    //        clientTest.doPOSTParam();
        }
    
    
        /**
         *
         * @description: 執行普通的GET請求,
         * 打開一個url,抓取響應結果輸出成html文件
         * @param: []
         * @return: void
         * @date: 2020/8/1
         */
        public void doGet() throws Exception{
    
            // 創建Httpclient對象
            CloseableHttpClient httpclient = HttpClients.createDefault();
            // 創建http GET請求
            HttpGet httpGet = new HttpGet("http://www.baidu.com");
            CloseableHttpResponse response = null;
            try {
                // 執行請求
                response = httpclient.execute(httpGet);
                // 判斷返回狀態是否為200
                if (response.getStatusLine().getStatusCode() == 200) {
                    //請求體內容
                    String content = EntityUtils.toString(response.getEntity(), "UTF-8");
                    //內容寫入文件
                    FileUtils.writeStringToFile(new File("D:\\baidu.html"), content, "UTF-8");
                    System.out.println("內容長度:"+content.length());
                }
            } finally {
                if (response != null) {
                    response.close();
                }
                //相當于關閉瀏覽器
                httpclient.close();
            }
    
        }
    
    
    
        /**
         *
         * @description: 執行帶參數的GET請求
         * 模擬使用百度搜索關鍵字"njitzyd",并保存搜索結果為html文件
         * @param: []
         * @return: void
         * @date: 2020/8/1
         */
        public void doGETParam() throws Exception{
            // 創建Httpclient對象
            CloseableHttpClient httpclient = HttpClients.createDefault();
            // 定義請求的參數
            URI uri = new URIBuilder("http://www.baidu.com/s").setParameter("wd", "njitzyd").build();
            // 創建http GET請求
            HttpGet httpGet = new HttpGet(uri);
            //response 對象
            CloseableHttpResponse response = null;
            try {
                // 執行http get請求
                response = httpclient.execute(httpGet);
                // 判斷返回狀態是否為200
                if (response.getStatusLine().getStatusCode() == 200) {
                    String content = EntityUtils.toString(response.getEntity(), "UTF-8");
                    //內容寫入文件
                    FileUtils.writeStringToFile(new File("D:\\baidu-param.html"), content, "UTF-8");
                    System.out.println("內容長度:"+content.length());
                }
            } finally {
                if (response != null) {
                    response.close();
                }
                httpclient.close();
            }
        }
    
        /**
         *
         * @description:執行無參數的POST請求,并設置Header來偽裝瀏覽器請求
         * @param: []
         * @return: void
         * @date: 2020/8/1
         */
        public void doPOST() throws Exception{
    
            // 創建Httpclient對象
            CloseableHttpClient httpclient = HttpClients.createDefault();
            // 創建http POST請求
            HttpPost httpPost = new HttpPost("https://www.oschina.net/");
            //偽裝瀏覽器請求
            httpPost.setHeader("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/83.0.4103.61 Safari/537.36");
            CloseableHttpResponse response = null;
            try {
                // 執行請求
                response = httpclient.execute(httpPost);
                // 判斷返回狀態是否為200
                if (response.getStatusLine().getStatusCode() == 200) {
                    String content = EntityUtils.toString(response.getEntity(), "UTF-8");
                    //內容寫入文件
                    FileUtils.writeStringToFile(new File("D:\\oschina.html"), content, "UTF-8");
                    System.out.println("內容長度:"+content.length());
                }
            } finally {
                if (response != null) {
                    response.close();
                }
                httpclient.close();
            }
        }
    
        /**
         *
         * @description: 執行帶參數的POST請求
         * 模擬開源中國檢索java,并偽裝瀏覽器請求,輸出響應結果為html文件
         * @param: []
         * @return: void
         * @date: 2020/8/1 
         */
        public void doPOSTParam() throws Exception {
            // 創建Httpclient對象
            CloseableHttpClient httpclient = HttpClients.createDefault();
            // 創建http POST請求
            HttpPost httpPost = new HttpPost("https://www.oschina.net/search");
            // 設置2個post參數,一個是scope、一個是q
            List<NameValuePair> parameters = new ArrayList<NameValuePair>(0);
            parameters.add(new BasicNameValuePair("scope", "project"));
            parameters.add(new BasicNameValuePair("q", "java"));
            // 構造一個form表單式的實體
            UrlEncodedFormEntity formEntity = new UrlEncodedFormEntity(parameters);
            // 將請求實體設置到httpPost對象中
            httpPost.setEntity(formEntity);
            //偽裝瀏覽器
            httpPost.setHeader("User-Agent",
                    "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/83.0.4103.61 Safari/537.36");
            CloseableHttpResponse response = null;
            try {
                // 執行請求
                response = httpclient.execute(httpPost);
                // 判斷返回狀態是否為200
                if (response.getStatusLine().getStatusCode() == 200) {
                    String content = EntityUtils.toString(response.getEntity(), "UTF-8");
                    //內容寫入文件
                    FileUtils.writeStringToFile(new File("D:\\oschina-param.html"), content, "UTF-8");
                    System.out.println("內容長度:"+content.length());
                }
            } finally {
                if (response != null) {
                    response.close();
                }
                httpclient.close();
            }
        }
    }
    
    
  1. 檢測結果

執行第一個可以看到在D盤下有個新的文件 baidu.html

image-20200802105730285

執行第二個可以生成baidu-param.html

image-20200802110019017

其他兩個類似,測試成功!!!

RestTemplate 簡介

Spring 提供了一個RestTemplate模板工具類,對基于Http的客戶端進行了封裝,并且實現了對象與json的序列化與反序列化,非常方便(上面的HttpClient返回的相應是json格式的)。RestTemplate 并沒有限定Http客戶端類型,而是進行了抽象,目前常用的三種都支持:

  • HttpClient
  • OKHttp
  • JDK原生的URLConnection(默認的)

具體使用

如果是基于SpringBoot 項目就引入那個web啟動器然后通過@bean注入一個restTemplate實例就好,這里我以普通的maven項目為例講解。

  1. 引入依賴
 <!--restTemplate 的支持-->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-web</artifactId>
            <version>5.1.8.RELEASE</version>
        </dependency>
  1. 編寫測試
public class RestTemplateTest {

    public static void main(String[] args) {
        new RestTemplateTest().testRestTemplate();
    }

    /**
     * 測試默認的實現
     */
    public void testRestTemplate(){
        ResponseEntity<String> forEntity = getRestTemplate().getForEntity("http://www.baidu.com", String.class);
        System.out.println(forEntity.toString());

        // 還可以有很多方法

    }


    public static RestTemplate getRestTemplate(){

        RestTemplate restTemplate = new RestTemplate();
        // 如果想要修改默認的實現方案,可以在new 的時候給他一個初始化的對象
        // 或者設置setRequestFactory方法來改變
//        RestTemplate restTemplate = new RestTemplate(new HttpComponentsClientHttpRequestFactory());
//        restTemplate.setRequestFactory(new HttpComponentsClientHttpRequestFactory());
        return restTemplate;
    }
}

  1. 可以看到控制臺打印出百度的頁面,測試成功?。?!

總結

一般的項目使用HttpClient 就可以滿足需求,當然在spring 尤其是在 SpringBoot 項目中 使用 RestTemplate 會更加方便??!

如果對你有所幫助,希望點贊!??!

?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。