HttpClient

知識概述

HttpClient 是 Apache Jakarta Common 下的子項目,能夠用來提供高效的、最新的、功能豐富的支持 HTTP 協議的客戶端編程工具包,而且它支持 HTTP 協議最新的版本和建議。java

HttpClient的主要功能:

  • 實現了全部 HTTP 的方法(GET、POST、PUT、HEAD、DELETE、HEAD、OPTIONS 等)
  • 支持 HTTPS 協議
  • 支持代理服務器(Nginx等)等
  • 支持自動(跳轉)轉向

HttpClient入門案例

1.添加httpClient jar包web

 <dependency>

         <groupId>org.apache.httpcomponents</groupId>

         <artifactId>httpclient</artifactId>

      </dependency>

 

     2.實現類spring

public class TestHttpClient {
    
    /**
     * 1.實例化httpClient對象
     * 2.準備url請求地址  https://www.baidu.com/
     * 3.封裝請求方式對象   GET/POST/PUT/DELETE
     * 4.發起http請求.獲取服務器響應.
     * 5.判斷返回值狀態碼信息 200.
     * 6.從響應對象中獲取服務器返回值數據.
     * @throws IOException 
     * @throws ClientProtocolException 
     */
    
@Test
    public void testGet() throws ClientProtocolException, IOException {
        CloseableHttpClient client = 
                            HttpClients.createDefault();
        String url = "https://www.baidu.com";
        HttpGet get = new HttpGet(url);
        CloseableHttpResponse response = 
                            client.execute(get);
        if(response.getStatusLine().getStatusCode() == 200) {
            //表示請求服務正確
            HttpEntity entity = response.getEntity();//返回值實體對象
            String result = 
                    EntityUtils.toString(entity, "UTF-8");
            System.out.println(result);
        }
    }
    
}

 

GET無參

HttpClient發送示例:apache

@Test
public void doGetTestOne() {
        // 得到Http客戶端(能夠理解爲:你得先有一個瀏覽器;注意:實際上HttpClient與瀏覽器是不同的)
        CloseableHttpClient httpClient = HttpClientBuilder.create().build();
        // 建立Get請求
        HttpGet httpGet = new HttpGet("http://localhost:12345/doGetControllerOne");
 
        // 響應模型
        CloseableHttpResponse response = null;
        try {
            // 由客戶端執行(發送)Get請求
            response = httpClient.execute(httpGet);
            // 從響應模型中獲取響應實體
            HttpEntity responseEntity = response.getEntity();
            System.out.println("響應狀態爲:" + response.getStatusLine());
            if (responseEntity != null) {
                System.out.println("響應內容長度爲:" + responseEntity.getContentLength());
                System.out.println("響應內容爲:" + EntityUtils.toString(responseEntity));
            }
        } catch (ClientProtocolException e) {
            e.printStackTrace();
        } catch (ParseException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            try {
                // 釋放資源
                if (httpClient != null) {
                    httpClient.close();
                }
                if (response != null) {
                    response.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

 對應接收示例:編程

 

 

GET有參(方式一:直接拼接URL):

HttpClient發送示例:json

 

/**
     * GET---有參測試 (方式一:手動在url後面加上參數)
     *
     * @date 2018年7月13日 下午4:19:23
     */
    @Test
    public void doGetTestWayOne() {
        // 得到Http客戶端(能夠理解爲:你得先有一個瀏覽器;注意:實際上HttpClient與瀏覽器是不同的)
        CloseableHttpClient httpClient = HttpClientBuilder.create().build();
 
        // 參數
        StringBuffer params = new StringBuffer();
        try {
            // 字符數據最好encoding如下;這樣一來,某些特殊字符才能傳過去(如:某人的名字就是「&」,不encoding的話,傳不過去)
            params.append("name=" + URLEncoder.encode("&", "utf-8"));
            params.append("&");
            params.append("age=24");
        } catch (UnsupportedEncodingException e1) {
            e1.printStackTrace();
        }
 
        // 建立Get請求
        HttpGet httpGet = new HttpGet("http://localhost:12345/doGetControllerTwo" + "?" + params);
        // 響應模型
        CloseableHttpResponse response = null;
        try {
            // 配置信息
            RequestConfig requestConfig = RequestConfig.custom()
                    // 設置鏈接超時時間(單位毫秒)
                    .setConnectTimeout(5000)
                    // 設置請求超時時間(單位毫秒)
                    .setConnectionRequestTimeout(5000)
                    // socket讀寫超時時間(單位毫秒)
                    .setSocketTimeout(5000)
                    // 設置是否容許重定向(默認爲true)
                    .setRedirectsEnabled(true).build();
 
            // 將上面的配置信息 運用到這個Get請求裏
            httpGet.setConfig(requestConfig);
 
            // 由客戶端執行(發送)Get請求
            response = httpClient.execute(httpGet);
 
            // 從響應模型中獲取響應實體
            HttpEntity responseEntity = response.getEntity();
            System.out.println("響應狀態爲:" + response.getStatusLine());
            if (responseEntity != null) {
                System.out.println("響應內容長度爲:" + responseEntity.getContentLength());
                System.out.println("響應內容爲:" + EntityUtils.toString(responseEntity));
            }
        } catch (ClientProtocolException e) {
            e.printStackTrace();
        } catch (ParseException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            try {
                // 釋放資源
                if (httpClient != null) {
                    httpClient.close();
                }
                if (response != null) {
                    response.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

 對應接收實例:瀏覽器

 

 

POST有參(普通參數):

注:POST傳遞普通參數時,方式與GET同樣便可,這裏以直接在url後綴上參數的方式示例。服務器

HttpClient發送示例:多線程

@Test
    public void doPostTestFour() {
 
        // 得到Http客戶端(能夠理解爲:你得先有一個瀏覽器;注意:實際上HttpClient與瀏覽器是不同的)
        CloseableHttpClient httpClient = HttpClientBuilder.create().build();
 
        // 參數
        StringBuffer params = new StringBuffer();
        try {
            // 字符數據最好encoding如下;這樣一來,某些特殊字符才能傳過去(如:某人的名字就是「&」,不encoding的話,傳不過去)
            params.append("name=" + URLEncoder.encode("&", "utf-8"));
            params.append("&");
            params.append("age=24");
        } catch (UnsupportedEncodingException e1) {
            e1.printStackTrace();
        }
 
        // 建立Post請求
        HttpPost httpPost = new HttpPost("http://localhost:12345/doPostControllerFour" + "?" + params);
 
        // 設置ContentType(注:若是隻是傳普通參數的話,ContentType不必定非要用application/json)
        httpPost.setHeader("Content-Type", "application/json;charset=utf8");
 
        // 響應模型
        CloseableHttpResponse response = null;
        try {
            // 由客戶端執行(發送)Post請求
            response = httpClient.execute(httpPost);
            // 從響應模型中獲取響應實體
            HttpEntity responseEntity = response.getEntity();
 
            System.out.println("響應狀態爲:" + response.getStatusLine());
            if (responseEntity != null) {
                System.out.println("響應內容長度爲:" + responseEntity.getContentLength());
                System.out.println("響應內容爲:" + EntityUtils.toString(responseEntity));
            }
        } catch (ClientProtocolException e) {
            e.printStackTrace();
        } catch (ParseException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            try {
                // 釋放資源
                if (httpClient != null) {
                    httpClient.close();
                }
                if (response != null) {
                    response.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

對應接收示例:併發

   Spring整合HttpClient

1.編輯pro配置文件

#最大鏈接數
http.maxTotal = 1000
#併發數
http.defaultMaxPerRoute = 20
#建立鏈接的最長時間
http.connectTimeout=5000
#從鏈接池中獲取到鏈接的最長時間
http.connectionRequestTimeout=500
#數據傳輸的最長時間
http.socketTimeout=5000
#提交請求前測試鏈接是否可用
http.staleConnectionCheckEnabled=true

 

2.編輯配置類

 

package com.jt.config;

import org.apache.http.client.config.RequestConfig;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClientBuilder;
import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.PropertySource;

@Configuration
@PropertySource(value="classpath:/properties/httpClient.properties")
public class HttpClientConfig {
    @Value("${http.maxTotal}")
    private Integer maxTotal;                        //最大鏈接數

    @Value("${http.defaultMaxPerRoute}")
    private Integer defaultMaxPerRoute;                //最大併發連接數

    @Value("${http.connectTimeout}")
    private Integer connectTimeout;                    //建立連接的最大時間

    @Value("${http.connectionRequestTimeout}") 
    private Integer connectionRequestTimeout;        //連接獲取超時時間

    @Value("${http.socketTimeout}")
    private Integer socketTimeout;                      //數據傳輸最長時間

    @Value("${http.staleConnectionCheckEnabled}")
    private boolean staleConnectionCheckEnabled;     //提交時檢查連接是否可用

    //定義httpClient連接池
    @Bean(name="httpClientConnectionManager")
    public PoolingHttpClientConnectionManager getPoolingHttpClientConnectionManager() {
        PoolingHttpClientConnectionManager manager = new PoolingHttpClientConnectionManager();
        manager.setMaxTotal(maxTotal);  //設定最大連接數
        manager.setDefaultMaxPerRoute(defaultMaxPerRoute);  //設定併發連接數
        return manager;
    }

    //定義HttpClient
    /**
     * 實例化鏈接池,設置鏈接池管理器。
     * 這裏須要以參數形式注入上面實例化的鏈接池管理器
      @Qualifier 指定bean標籤進行注入
     */
    @Bean(name = "httpClientBuilder")
    public HttpClientBuilder getHttpClientBuilder(@Qualifier("httpClientConnectionManager")PoolingHttpClientConnectionManager httpClientConnectionManager){

        //HttpClientBuilder中的構造方法被protected修飾,因此這裏不能直接使用new來實例化一個HttpClientBuilder,可使用HttpClientBuilder提供的靜態方法create()來獲取HttpClientBuilder對象
        HttpClientBuilder httpClientBuilder = HttpClientBuilder.create();
        httpClientBuilder.setConnectionManager(httpClientConnectionManager);
        return httpClientBuilder;
    }

    /**
     *     注入鏈接池,用於獲取httpClient
     * @param httpClientBuilder
     * @return
     */
    @Bean
    public CloseableHttpClient getCloseableHttpClient(@Qualifier("httpClientBuilder") HttpClientBuilder httpClientBuilder){

        return httpClientBuilder.build();
    }

    /**
     * Builder是RequestConfig的一個內部類
      * 經過RequestConfig的custom方法來獲取到一個Builder對象
      * 設置builder的鏈接信息
     * @return
     */
    @Bean(name = "builder")
    public RequestConfig.Builder getBuilder(){
        RequestConfig.Builder builder = RequestConfig.custom();
        return builder.setConnectTimeout(connectTimeout)
                .setConnectionRequestTimeout(connectionRequestTimeout)
                .setSocketTimeout(socketTimeout)
                .setStaleConnectionCheckEnabled(staleConnectionCheckEnabled);
    }

    /**
     * 使用builder構建一個RequestConfig對象
     * @param builder
     * @return
     */
    @Bean
    public RequestConfig getRequestConfig(@Qualifier("builder") RequestConfig.Builder builder){
        return builder.build();
    }
}

 

 

3. 編輯關閉鏈接配置文件

package com.jt.config;

import javax.annotation.PreDestroy;

import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
import org.apache.http.pool.PoolStats;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

@Component    //交給spring容器管理
public class HttpClientClose extends Thread{
    @Autowired
    private PoolingHttpClientConnectionManager manage;
    private volatile boolean shutdown;    //開關 volatitle表示多線程可變數據,一個線程修改,其餘線程當即修改
    
    public HttpClientClose() {
        ///System.out.println("執行構造方法,實例化對象");
        //線程開啓啓動
        this.start();
    }
    
    
    @Override
    public void run() {
        try {
            //若是服務沒有關閉,執行線程
            while(!shutdown) {
                synchronized (this) {
                    wait(5000);            //等待5秒
                    //System.out.println("線程開始執行,關閉超時連接");
                    //關閉超時的連接
                    PoolStats stats = manage.getTotalStats();
                    int av = stats.getAvailable();    //獲取可用的線程數量
                    int pend = stats.getPending();    //獲取阻塞的線程數量
                    int lea = stats.getLeased();    //獲取當前正在使用的連接數量
                    int max = stats.getMax();
                    //System.out.println("max/"+max+":    av/"+av+":  pend/"+pend+":   lea/"+lea);
                    manage.closeExpiredConnections();
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
            throw new RuntimeException();
        }

        super.run();
    }

    //關閉清理無效鏈接的線程
    @PreDestroy    //容器關閉時執行該方法.
    public void shutdown() {
        shutdown = true;
        synchronized (this) {
            //System.out.println("關閉所有連接!!");
            notifyAll(); //所有從等待中喚醒.執行關閉操做;
        }
    }
}

 

5. 編輯工具API

package com.jt.util;

import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

import org.apache.http.HttpEntity;
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.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.client.utils.URIBuilder;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.util.EntityUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

@Service
public class HttpClientService {
    
    @Autowired
    private CloseableHttpClient httpClient;
    @Autowired
    private RequestConfig requestConfig;
    
    /**
     *    編輯工具API目的簡化代碼,實現鬆耦合
     *   
     *    做用:幫助用戶發起http請求,獲取正確的結果返回給用戶
     *    參數設計:    1.用戶url地址   2.Map<參數名,參數值>  3.字符編碼
     * 
     * get請求方式:
     *     1.沒有參數時: http://www.baidu.com
     *     2.有參數時:     http://www.baidu.com?key1=value1&key2=value2...
     * @param url
     * @param params
     * @param charset
     * @return
     */
    public String doGet(String url,Map<String,String> params,String charset) {
        //1.校驗用戶是否傳遞字符編碼
        if(StringUtils.isEmpty(charset)) {
            
            charset = "UTF-8";
        }
        
        //2.封裝URL地址
        //  http://www.baidu.com?key1=value1&key2=value2&...
        if(params != null) {
            url = url + "?";
            //map遍歷
            for (Map.Entry<String,String> entry : params.entrySet()) {
                String key = entry.getKey();
                String value = entry.getValue();
                url += key+"="+value+"&";
            }
            //截去多餘的&
            url = url.substring(0, url.length()-1);
        }
        
        //3.定義httpGet請求對象
        HttpGet httpGet = new HttpGet(url);
        //設定請求的超時時間
        httpGet.setConfig(requestConfig);
        
        //定義返回值數據
        String result = null;
        try {
            CloseableHttpResponse response = httpClient.execute(httpGet);
            if(response.getStatusLine().getStatusCode() == 200) {
                //表示請求正確
                HttpEntity entity = response.getEntity();
                result = EntityUtils.toString(entity,charset);
            }
        } catch (Exception e) {
            e.printStackTrace();
            throw new RuntimeException(e);
        }
        
        return result;
    }
    
    //重載方法
    public String doGet(String url) {
        
        return doGet(url, null, null);
    }
    
    public String doGet(String url,Map<String,String> params) {
        
        return doGet(url, params, null);
    }
    
    
    
    //實現httpClient POST提交
    public String doPost(String url,Map<String,String> params,String charset){
        String result = null;

        //1.定義請求類型
        HttpPost post = new HttpPost(url);
        post.setConfig(requestConfig);      //定義超時時間

        //2.判斷字符集是否爲null
        if(StringUtils.isEmpty(charset)){

            charset = "UTF-8";
        }

        //3.判斷用戶是否傳遞參數
        if(params !=null){
            //3.2準備List集合信息
            List<NameValuePair> parameters = 
                    new ArrayList<>();

            //3.3將數據封裝到List集合中
            for (Map.Entry<String,String> entry : params.entrySet()) {

                parameters.add(new BasicNameValuePair(entry.getKey(), entry.getValue()));
            }

            //3.1模擬表單提交
            try {
                UrlEncodedFormEntity formEntity = 
                        new UrlEncodedFormEntity(parameters,charset); //採用u8編碼

                //3.4將實體對象封裝到請求對象中
                post.setEntity(formEntity);
            } catch (UnsupportedEncodingException e) {

                e.printStackTrace();
            }
        }

        //4.發送請求
        try {
            CloseableHttpResponse response = 
                    httpClient.execute(post);

            //4.1判斷返回值狀態
            if(response.getStatusLine().getStatusCode() == 200) {

                //4.2表示請求成功
                result = EntityUtils.toString(response.getEntity(),charset);
            }else{
                System.out.println("獲取狀態碼信息:"+response.getStatusLine().getStatusCode());
                throw new RuntimeException();
            }
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }

        return result;
    }



    public String doPost(String url){

        return doPost(url, null, null);
    }

    public String doPost(String url,Map<String,String> params){

        return doPost(url, params, null);
    }

    public String doPost(String url,String charset){

        return doPost(url, null, charset);
    }
}

 

6.編輯測試類調試程序

@Autowired
    private HttpClientService httpClient;
    
    @Test
    public void doGet() {
        //http://manage.jt.com/web/item/findItemById?itemId=1474391969
        String url = 
        "http://manage.jt.com/web/item/findItemById";
        Map<String,String> params = new HashMap<>();
        params.put("itemId", "562379");
        String json = httpClient.doGet(url, params);
        System.out.println(json);
    }
相關文章
相關標籤/搜索
本站公眾號
   歡迎關注本站公眾號,獲取更多信息