Apache HttpClient和HttpAsyncClient應用


官網地址 http://hc.apache.org/
官方PDF地址: http://hc.apache.org/httpcomponents-core-ga/tutorial/pdf/httpcore-tutorial.pdf

HttpClient是基於HttpCore的HTTP / 1.1兼容HTTP代理實現。 它還為客戶端身份驗證,HTTP狀態管理和HTTP連接管理提供可重用的組件。 HttpComponents Client是Commons HttpClient 3.x的繼承者和替代者。 強烈建議Commons HttpClient用戶進行升級。
HttpClient 特性

  • 基於標准的純Java,HTTP版本1.0和1.1的實現
  • 在可擴展的OO框架中完全實現所有HTTP方法(GET,POST,PUT,DELETE,HEAD,OPTIONS和TRACE)。
  • 支持使用HTTPS(基於SSL的HTTP)協議進行加密。
  • 通過HTTP代理的透明連接。
  • 通過CONNECT方法通過HTTP代理建立的HTTPS連接隧道。
  • 基本,摘要,NTLMv1,NTLMv2,NTLM2會話,SNPNEGO,Kerberos身份驗證方案。
  • 用於自定義身份驗證方案的插件機制。
  • 可插拔的安全套接字工廠,使使用第三方解決方案更加容易
  • 在多線程應用程序中使用的連接管理支持。支持設置
  • 最大總連接數以及每個主機的最大連接數。檢測並關閉陳舊的連接。
  • 自動Cookie處理,用於從服務器讀取Set-Cookie:標頭,並在適當時在Cookie:標頭中發回。
  • 自定義Cookie策略的插件機制。
  • 請求輸出流,以避免通過直接流到服務器的套接字來緩沖任何內容主體。
  • 響應輸入流,通過直接從套接字流傳輸到服務器來有效讀取響應主體。
  • 在HTTP / 1.0中使用KeepAlive的持久連接和在HTTP / 1.1中的持久性
  • 直接訪問服務器發送的響應代碼和標頭。
  • 設置連接超時的能力。
  • 支持HTTP / 1.1響應緩存。

Asynch HttpClient是基於HttpCore NIO和HttpClient組件的HTTP / 1.1兼容HTTP代理實現。 它是Apache HttpClient的補充模塊,適用於特殊情況,在特殊情況下,就原始數據吞吐量而言,處理大量並發連接的能力比性能更為重要。
HttpAsyncClient特性

  • 基於標准的純Java,HTTP版本1.0和1.1的實現
  • 在可擴展的OO框架中完全實現所有HTTP方法(GET,POST,PUT,DELETE,HEAD,OPTIONS和TRACE)。
  • 支持使用HTTPS(基於SSL的HTTP)協議進行加密。
  • 通過HTTP代理的透明連接。\
  • 通過CONNECT方法通過HTTP代理建立的HTTPS連接隧道。
  • 連接管理支持並發請求執行。支持設置最大總連接數以及每個主機的最大連接數。檢測並關閉過期的連接。
  • 在HTTP / 1.0中使用KeepAlive的持久連接和在HTTP / 1.1中的持久性
  • 設置連接超時的能力。
  • 源代碼可根據Apache許可免費獲得。
  • 基本,摘要,NTLMv1,NTLMv2,NTLM2會話,SNPNEGO和Kerberos身份驗證方案。
  • 用於自定義身份驗證方案的插件機制。
  • 自動Cookie處理,用於從服務器讀取Set-Cookie:標頭,並在適當時在Cookie:標頭中發回。
  • 自定義Cookie策略的插件機制。
  • 支持HTTP / 1.1響應緩存。
  • 支持流水線的請求執行和處理。

前言

​ 超文本傳輸協議(HTTP)可能是當今Internet上使用的最重要的協議。 Web服務,支持網絡的設備和網絡計算的增長繼續將HTTP協議的作用擴展到用戶驅動的Web瀏覽器之外,同時增加了需要HTTP支持的應用程序的數量。
​ 盡管java.net軟件包提供了用於通過HTTP訪問資源的基本功能,但它並未提供許多應用程序所需的全部靈活性或功能。 HttpClient試圖填補這一點通過提供高效,最新且功能豐富的軟件包來實現最新的HTTP標准和建議的客戶端,從而使此方法無效
​ HttpClient是為擴展而設計的,同時提供對基本HTTP協議的強大支持,對於構建HTTP感知的客戶端應用程序(例如Web瀏覽器,Web服務)的任何人來說,HttpClient可能都會感興趣客戶端或利用或擴展HTTP協議進行分布式通信的系統。

  1. HttpClient作用域

  • 基於HttpCore的客戶端HTTP傳輸庫

  • 基於經典(阻塞)I / O

  • 內容不可知

  1. HttpClient不是什么

HttpClient不是瀏覽器。 它是客戶端HTTP傳輸庫。 HttpClient的目的是傳輸和接收HTTP消息,HttpClient將不會嘗試處理內容,執行HTML頁面中嵌入的javascript,嘗試猜測內容類型(如果未顯式設置),重新格式化請求/重寫位置URI或其他與HTTP傳輸無關的功能。
最新Pom引入

   <dependency>
            <groupId>org.apache.httpcomponents</groupId>
            <artifactId>httpasyncclient</artifactId>
            <version>4.1.4</version>
        </dependency>

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

在這里插入圖片描述
在這里插入圖片描述
HttpClient連接池簡單封裝
支持https 無須認證請求

import com.alibaba.fastjson.JSONObject;
import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.HttpStatus;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.ResponseHandler;
import org.apache.http.client.config.RequestConfig;
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.config.Registry;
import org.apache.http.config.RegistryBuilder;
import org.apache.http.config.SocketConfig;
import org.apache.http.conn.DnsResolver;
import org.apache.http.conn.HttpConnectionFactory;
import org.apache.http.conn.ManagedHttpClientConnection;
import org.apache.http.conn.routing.HttpRoute;
import org.apache.http.conn.socket.ConnectionSocketFactory;
import org.apache.http.conn.socket.PlainConnectionSocketFactory;
import org.apache.http.conn.ssl.NoopHostnameVerifier;
import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
import org.apache.http.conn.ssl.TrustStrategy;
import org.apache.http.entity.ByteArrayEntity;
import org.apache.http.entity.ContentType;
import org.apache.http.impl.DefaultConnectionReuseStrategy;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.DefaultConnectionKeepAliveStrategy;
import org.apache.http.impl.client.DefaultHttpRequestRetryHandler;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.impl.conn.DefaultHttpResponseParserFactory;
import org.apache.http.impl.conn.ManagedHttpClientConnectionFactory;
import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
import org.apache.http.impl.conn.SystemDefaultDnsResolver;
import org.apache.http.impl.io.DefaultHttpRequestWriterFactory;
import org.apache.http.ssl.SSLContextBuilder;
import org.apache.http.util.EntityUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.net.ssl.SSLContext;
import java.io.IOException;
import java.io.Serializable;
import java.net.URI;
import java.nio.charset.StandardCharsets;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
import java.util.concurrent.TimeUnit;


/**
 * @author Created by niugang on 2020/3/25/15:13
 * HttpClient實現應該是線程安全的。 建議將此類的相同實例重用於多個請求執行。
 */
public class HttpClientV2Utils {

    private static final Logger LOGGER = LoggerFactory.getLogger(HttpClientV2Utils.class);

    public static CloseableHttpClient httpClient = null;


    /**
     * 獲取HttpClient工具類
     *
     * @return CloseableHttpClient
     * @throws Exception Exception
     */
    public static synchronized CloseableHttpClient getHttpClient() throws Exception {
        if (httpClient == null) {

            //使用 loadTrustMaterial() 方法實現一個信任策略,信任所有證書
            SSLContext sslContext = new SSLContextBuilder().loadTrustMaterial(null, new TrustStrategy() {
                // 信任所有
                @Override
                public boolean isTrusted(X509Certificate[] chain, String authType) throws CertificateException {
                    return true;
                }
            }).build();
            // 該主機名驗證程序實際上關閉了主機名驗證。 它接受任何有效的SSL會話並匹配目標主機
            SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory(sslContext, NoopHostnameVerifier.INSTANCE);

            //為支持的協議方案創建自定義連接套接字工廠的注冊表。
            Registry<ConnectionSocketFactory> socketFactoryRegistry = RegistryBuilder.<ConnectionSocketFactory>create()
                    .register("http", PlainConnectionSocketFactory.INSTANCE)
                    .register("https", sslsf)
                    .build();

            //HTTPConnection工廠 :配置請求/解析響應
            HttpConnectionFactory<HttpRoute, ManagedHttpClientConnection> connFactory = new ManagedHttpClientConnectionFactory(
                    DefaultHttpRequestWriterFactory.INSTANCE, DefaultHttpResponseParserFactory.INSTANCE);
            //DNS解析器
            DnsResolver dnsResolver = SystemDefaultDnsResolver.INSTANCE;

            //創建池化管理器
            PoolingHttpClientConnectionManager manager = new PoolingHttpClientConnectionManager(
                    socketFactoryRegistry, connFactory, dnsResolver);
            // 默認為Socket配置
            SocketConfig socketConfig = SocketConfig.custom()
                    .setTcpNoDelay(true)
                    .build();
            manager.setDefaultSocketConfig(socketConfig);
            // 配置永久連接的最大總數或每個路由限制
            // 可以保留在池中或由連接管理器租用。
            //每個路由的默認最大連接,每個路由實際最大連接為默認為DefaultMaxPreRoute控制,而MaxTotal是控制整個池子最大數
            manager.setMaxTotal(100);
            manager.setDefaultMaxPerRoute(10);
            // 在從連接池獲取連接時,連接不活躍多長時間后需要進行一次驗證,默認為2s
            manager.setValidateAfterInactivity(5 * 1000);

            //默認請求配置
            //設置連接超時時間 4s
            //設置等待數據超時時間,5s
            //設置從連接池獲取連接的等待超時時間
            RequestConfig defaultRequestConfig = RequestConfig.custom()
                    .setConnectTimeout(4 * 1000)
                    .setSocketTimeout(5 * 1000)
                    .setConnectionRequestTimeout(2000)
                    .build();

            httpClient = HttpClients.custom()
                    .setConnectionManager(manager)
                    .setDefaultRequestConfig(defaultRequestConfig)
                    //連接池不是共享模式
                    .setConnectionManagerShared(false)
                    .evictIdleConnections(60, TimeUnit.SECONDS)
                    //定期回收空閑連接
                    .evictExpiredConnections()
                    .setConnectionTimeToLive(60, TimeUnit.SECONDS)
                    //連接重用策略,即是否能keeplive
                    .setConnectionReuseStrategy(DefaultConnectionReuseStrategy.INSTANCE)
                    //長連接配置,即獲取長連接生產多長時間
                    .setKeepAliveStrategy(DefaultConnectionKeepAliveStrategy.INSTANCE)
                    //設置重試次數,默認為3次;當前禁用掉(根據需要重啟)
                    .setRetryHandler(new DefaultHttpRequestRetryHandler(0, false))
                    .build();
            // jvm 停止或重啟時,關閉連接池釋放連接資源(跟數據庫連接池類似)
            Runtime.getRuntime().addShutdownHook(new Thread() {
                @Override
                public void run() {
                    try {
                        httpClient.close();
                    } catch (IOException e) {
                        LOGGER.error("HttpClient close exception", e);
                    }
                }
            });

        }

        return httpClient;
    }

    /**
     * get方法封裝
     * <p>
     * 要使用     EntityUtils.consume(response.getEntity());或者EntityUtils.toString(response.getEntity());
     * 消費響應,不推薦HttpEntity.getContent.close方法來釋放連接,處理不好異常將導致連接不釋放,也不推薦CloseableHttpClient#close關閉連接,它將直接關閉
     * socket,導致長連接不能復用
     *
     * @param httpGet httpGet
     * @return String
     */
    private static String doGet(HttpGet httpGet) {
        HttpResponse response = null;
        try {
            response = getHttpClient().execute(httpGet);
            if (response.getStatusLine().getStatusCode() != HttpStatus.SC_OK) {
                if (response.getEntity() != null) {
                    EntityUtils.consume(response.getEntity());
                }
                LOGGER.info("GET execute exception [{}]->[{}]", response.getStatusLine(), response.getStatusLine().getReasonPhrase());
                return "error";
            } else {
                return EntityUtils.toString(response.getEntity());
            }
        } catch (Exception e) {
            if (response != null) {
                try {
                    EntityUtils.consume(response.getEntity());
                } catch (IOException e1) {
                    LOGGER.info("GET consume response entity exception", e);
                }
            }
        }

        return "error";
    }

    public static void main(String[] args) throws Exception {
        HttpGet httpsget = new HttpGet("https://11.12.115.104:8443/bs/gateway/get.do");
        httpsget.setHeader("token", "c50e18bc01a62d395a9755b523bc2e50");
        String s = doGet(httpsget);
        LOGGER.info("doGet :{}", s);

        //####1.HTTPS get請求驗證 方式二
        URI uri = new URIBuilder()
                .setScheme("https")
                .setHost("11.12.115.104")
                .setPort(8443)
                .setPath("/bs/gateway/get.do")
                .build();

        HttpGet httpsget1 = new HttpGet(uri);
        httpsget1.setHeader("token", "12fd6749989c7aa60ef34c8d53c0cf71");
        // 自定義響應處理器
        ResponseHandler<String> responseHandler = new ResponseHandler<String>() {

            @Override
            public String handleResponse(
                    final HttpResponse response) throws IOException {
                int status = response.getStatusLine().getStatusCode();
                if (status >= 200 && status < 300) {
                    HttpEntity entity = response.getEntity();
                    return entity != null ? EntityUtils.toString(entity, StandardCharsets.UTF_8) : null;
                } else {
                    throw new ClientProtocolException("Unexpected response status: " + status + "->" + response.getStatusLine().getReasonPhrase());
                }
            }

        };
        String execute = getHttpClient().execute(httpsget1, responseHandler);

        LOGGER.info("https get excute result {}", execute);
        //####2.Https Post請求驗證  請求體為json數據

        JSONObject jsonObject = new JSONObject();
        jsonObject.put("user", "44444");
        jsonObject.put("ip", "192.168.1.3");
        jsonObject.put("status", "0");
        ByteArrayEntity byteArrayEntity = new ByteArrayEntity(jsonObject.toJSONString().getBytes(), ContentType.create("application/json", "UTF-8"));

        HttpPost httpspost = new HttpPost("https://11.12.115.104:8443/accessControl/saveDevice.do");
        httpspost.setHeader("token", "12fd6749989c7aa60ef34c8d53c0cf71");
        httpspost.setEntity(byteArrayEntity);

        String httpsGostExecute = getHttpClient().execute(httpspost, responseHandler);

        LOGGER.info("https post excute result {}", httpsGostExecute);
        //####3.http get

        HttpGet httpGet = new HttpGet("http://www.baidu.com");
        String httpGetExecute = getHttpClient().execute(httpGet, responseHandler);

        LOGGER.info("http get excute result {}", httpGetExecute);


    }
}

HttpAsyncClient連接池簡單封裝


package com.example.demo.utils;

import lombok.SneakyThrows;
import org.apache.http.*;

import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.config.CookieSpecs;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.concurrent.FutureCallback;
import org.apache.http.config.ConnectionConfig;
import org.apache.http.config.Registry;
import org.apache.http.config.RegistryBuilder;
import org.apache.http.conn.DnsResolver;

import org.apache.http.conn.ssl.NoopHostnameVerifier;
import org.apache.http.conn.ssl.TrustSelfSignedStrategy;

import org.apache.http.conn.ssl.TrustStrategy;
import org.apache.http.impl.conn.SystemDefaultDnsResolver;
import org.apache.http.impl.nio.client.CloseableHttpAsyncClient;
import org.apache.http.impl.nio.client.HttpAsyncClients;
import org.apache.http.impl.nio.codecs.DefaultHttpRequestWriterFactory;

import org.apache.http.impl.nio.codecs.DefaultHttpResponseParserFactory;
import org.apache.http.impl.nio.conn.ManagedNHttpClientConnectionFactory;
import org.apache.http.impl.nio.conn.PoolingNHttpClientConnectionManager;
import org.apache.http.impl.nio.reactor.DefaultConnectingIOReactor;
import org.apache.http.impl.nio.reactor.IOReactorConfig;

import org.apache.http.nio.conn.ManagedNHttpClientConnection;
import org.apache.http.nio.conn.NHttpConnectionFactory;
import org.apache.http.nio.conn.NoopIOSessionStrategy;
import org.apache.http.nio.conn.SchemeIOSessionStrategy;
import org.apache.http.nio.conn.ssl.SSLIOSessionStrategy;
import org.apache.http.nio.reactor.ConnectingIOReactor;
import org.apache.http.nio.reactor.IOReactorException;
import org.apache.http.nio.util.HeapByteBufferAllocator;
import org.apache.http.ssl.SSLContextBuilder;
import org.apache.http.util.EntityUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import javax.net.ssl.SSLContext;
import java.io.IOException;
import java.nio.charset.CodingErrorAction;
import java.nio.charset.StandardCharsets;
import java.security.KeyManagementException;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
import java.util.concurrent.Future;


/**
 * 此示例演示如何自定義和配置HTTP請求執行和連接管理的最常見方面。
 *
 * @author Created by niugang on 2020/3/24/11:25
 */
public class HttpAsyncClientUtils {


    private static final Logger LOGGER = LoggerFactory.getLogger(HttpAsyncClientUtils.class);
    public static CloseableHttpAsyncClient httpclient = null;


    /**
     * 獲取 ttpAsyncClient
     *
     * @return CloseableHttpAsyncClient
     * @throws KeyStoreException        KeyStoreException
     * @throws NoSuchAlgorithmException NoSuchAlgorithmException
     * @throws IOReactorException       IOReactorException
     */
    public static synchronized CloseableHttpAsyncClient getHttpAsyncClient() throws KeyStoreException, NoSuchAlgorithmException, KeyManagementException, IOReactorException {
        if (httpclient == null) {


            // HTTPConnection工廠 :配置請求/解析響應
            NHttpConnectionFactory<ManagedNHttpClientConnection> connFactory = new ManagedNHttpClientConnectionFactory(
                    DefaultHttpRequestWriterFactory.INSTANCE, DefaultHttpResponseParserFactory.INSTANCE, HeapByteBufferAllocator.INSTANCE);


            //ssl 連接設置 無須證書也能訪問 https
            //使用 loadTrustMaterial() 方法實現一個信任策略,信任所有證書
            SSLContext sslContext = new SSLContextBuilder().loadTrustMaterial(null, new TrustStrategy() {
                // 信任所有
                @Override
                public boolean isTrusted(X509Certificate[] chain, String authType) throws CertificateException {
                    return true;
                }
            }).build();

            // 為支持的協議方案創建自定義連接套接字工廠的注冊表。
            Registry<SchemeIOSessionStrategy> sessionStrategyRegistry = RegistryBuilder.<SchemeIOSessionStrategy>create()
                    .register("http", NoopIOSessionStrategy.INSTANCE)
                    .register("https", new SSLIOSessionStrategy(sslContext, NoopHostnameVerifier.INSTANCE))
                    .build();

            //DNS解析器
            DnsResolver dnsResolver = SystemDefaultDnsResolver.INSTANCE;

            // Create I/O reactor configuration
            IOReactorConfig ioReactorConfig = IOReactorConfig.custom()
                    .setIoThreadCount(Runtime.getRuntime().availableProcessors())
                    .setConnectTimeout(30000)
                    .setSoTimeout(30000)
                    .build();

            // 創建一個定制的I/O reactort
            ConnectingIOReactor ioReactor = new DefaultConnectingIOReactor(ioReactorConfig);

            // 使用自定義配置創建連接管理器。
            PoolingNHttpClientConnectionManager connManager = new PoolingNHttpClientConnectionManager(
                    ioReactor, connFactory, sessionStrategyRegistry, dnsResolver);

            //創建連接配置
            ConnectionConfig connectionConfig = ConnectionConfig.custom()
                    .setMalformedInputAction(CodingErrorAction.IGNORE)
                    .setUnmappableInputAction(CodingErrorAction.IGNORE)
                    .setCharset(Consts.UTF_8)
                    .build();
            // 將連接管理器配置為默認使用或針對特定主機使用連接配置。
            connManager.setDefaultConnectionConfig(connectionConfig);

            // 配置永久連接的最大總數或每個路由限制
            // 可以保留在池中或由連接管理器租用。
            //每個路由的默認最大連接,每個路由實際最大連接為默認為DefaultMaxPreRoute控制,而MaxTotal是控制整個池子最大數
            connManager.setMaxTotal(100);
            connManager.setDefaultMaxPerRoute(10);


            // 創建全局請求配置
            RequestConfig defaultRequestConfig = RequestConfig.custom()
                    .setCookieSpec(CookieSpecs.DEFAULT)
                    .setSocketTimeout(5 * 1000)
                    .setConnectTimeout(5 * 1000)
                    .setExpectContinueEnabled(true)
                    .build();

            // Create an HttpClientUtils with the given custom dependencies and configuration.
            httpclient = HttpAsyncClients.custom()
                    .setConnectionManager(connManager)
                    .setDefaultRequestConfig(defaultRequestConfig)
                    .build();

            //jvm 停止或重啟時,關閉連接池釋放連接資源(跟數據庫連接池類似)
            Runtime.getRuntime().addShutdownHook(new Thread() {
                @Override
                public void run() {
                    try {
                        httpclient.close();
                    } catch (IOException e) {
                        LOGGER.error("HttpClient close exception", e);
                    }
                }
            });

        }
        return httpclient;
    }

    public static HttpResponse doGet(String url) {
        CloseableHttpAsyncClient httpAsyncClient = null;

        try {
            final HttpGet httpget = new HttpGet(url);


            LOGGER.info("Executing request {}", httpget.getRequestLine());
            httpAsyncClient = getHttpAsyncClient();

            httpAsyncClient.start();

            // Pass local context as a parameter
            Future<HttpResponse> future = httpAsyncClient.execute(httpget, new FutureCallback<HttpResponse>() {

                @SneakyThrows
                @Override
                public void completed(final HttpResponse response2) {
                    LOGGER.info("{} -> {} completed", httpget.getRequestLine(), response2.getStatusLine());
                }

                @Override
                public void failed(final Exception ex) {
                    LOGGER.error("{}->", httpget.getRequestLine(), ex);
                }

                @Override
                public void cancelled() {
                    LOGGER.error("{} cancelled", httpget.getRequestLine());
                }

            });
            //等待響應結果
            return future.get();
        } catch (Exception e) {
            LOGGER.error("GET execute exception ", e);
        } finally {
            if (httpAsyncClient != null) {
                //直接關閉socket,會導致長連接不能復用,所以返回Future,調用放調用get方法,將一直處於阻塞狀態
                try {
                    httpAsyncClient.close();
                } catch (IOException e) {
                    LOGGER.error("GET execute httpAsyncClient close exception ", e);
                }
            }

        }
        return null;
    }

    public static void main(String[] args) throws Exception {
        HttpResponse response = doGet("https://11.12.115.104:8443/serverStatus/serverInfo");
        if (response == null) {
            return;
        }
        LOGGER.info("Response: {}", response.getStatusLine());
        int status = response.getStatusLine().getStatusCode();
        if (status >= 200 && status < 300) {
            HttpEntity entity = response.getEntity();
            String res = entity != null ? EntityUtils.toString(entity, StandardCharsets.UTF_8) : null;
            LOGGER.info("result->{}", res);
        } else {
            throw new ClientProtocolException("Unexpected response status: " + status + "->" + response.getStatusLine().getReasonPhrase());
        }

    }

}

微信公眾號
在這里插入圖片描述


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM