• CloseableHttpClient的个性化配置


    CloseableHttpClient的个性化配置借助 HttpClientBuilder来完成,HttpClientBuilder线程不安全。

    调用 HttpClientBuilder实例方法除了build方法外,返回都是其本身,同时HttpClientBuilder 包含了诸多属性,并提供了对外的设置方法。

    /**
     * useSystemProperties() 是否读取系统属性, 调用该方法则可以读取
     * disableAuthCaching() 是否禁用缓, 调用该方法则禁用
     * disableRedirectHandling() 是否禁用重定向, 调用该方法则禁用
     * disableContentCompression() 是否禁用内容压缩, 调用该方法则禁用
     * disableAutomaticRetries() 是否禁用自动重试, 调用该方法则禁用
     * disableCookieManagement() 是否禁用cookie管理, 调用该方法则禁用
     * disableConnectionState() 是否禁用连接状态, 调用该方法则禁用
     *
     * setMaxConnTotal()  全局最大维持的连接数
     * setMaxConnPerRoute()  单个Route最大连接数
     * evictIdleConnections() 设置最长空闲时间及空闲时间的单位,
     *                      调用此方法会设置evictIdleConnections=true, 表示开启独立线程清理空闲连接
     * evictExpiredConnections() 开启独立线程清理过期连接
     *
     */

    1.setDefaultConnectionConfig()

    默认的Connection设置。

    HttpClientBuilder httpClientBuilder = HttpClients.custom();
    ConnectionConfig.Builder connectionConfigBuilder = ConnectionConfig.custom();
    //设置缓存区大小, 默认是8192(8kb)
    connectionConfigBuilder.setBufferSize(1024);
    //设置编码
    connectionConfigBuilder.setCharset(Consts.UTF_8);
    //设置碎片大小
    connectionConfigBuilder.setFragmentSizeHint(1024);
    //设置消息约束
    MessageConstraints messageConstraints = MessageConstraints.custom()
            .setMaxHeaderCount(200)
            .setMaxLineLength(2000)
            .build();
    connectionConfigBuilder.setMessageConstraints(messageConstraints);
    
    connectionConfigBuilder.setUnmappableInputAction(CodingErrorAction.IGNORE);
    connectionConfigBuilder.setMalformedInputAction(CodingErrorAction.IGNORE);
    ConnectionConfig configConfig = connectionConfigBuilder.build();
    //一般不修改HTTP connection相关配置,故不设置
    httpClientBuilder.setDefaultConnectionConfig(configConfig);

    2. setDefaultRequestConfig()

    HttpClientBuilder httpClientBuilder = HttpClients.custom();
    
    RequestConfig.Builder requestConfigBuilder = RequestConfig.custom();
    //以下方法除build()方法都是返回同一个RequestConfig.Builder实例,所以可以进行链式调用
    //连接超时时间, 单位毫秒
    requestConfigBuilder.setConnectTimeout(2000);
    //从池中获取连接超时时间
    requestConfigBuilder.setConnectionRequestTimeout(500);
    //读超时时间(等待数据超时时间)
    requestConfigBuilder.setSocketTimeout(2000);
    //该 API 在4.4中已过时, 可以通过ConnectionConfig中设置closeExpiredConnections和closeIdleConnections来关闭
    //确保获取到的连接都是可用连接
    requestConfigBuilder.setStaleConnectionCheckEnabled(true);
    //确定是否应自动处理身份验证
    requestConfigBuilder.setAuthenticationEnabled(true);
    //确定循环重定向(重定向到相同位置)是否应该重定向
    requestConfigBuilder.setCircularRedirectsAllowed(false);
    //重定向的最大数目。对重定向次数的限制是为了防止无限循环
    requestConfigBuilder.setMaxRedirects(5);
    //确定是否应拒绝相对重定向。HTTP规范要求位置值是一个绝对URI
    requestConfigBuilder.setRelativeRedirectsAllowed(true);
    //确定用于HTTP状态管理的cookie规范的名称
    requestConfigBuilder.setCookieSpec("");
    //返回用于请求执行的本地地址。在具有多个网络接口的计算机上,此参数可用于选择其中的网络接口连接产生。
    requestConfigBuilder.setLocalAddress();
    //代理配置
    requestConfigBuilder.setProxy();
    //在使用代理主机进行身份验证时,确定支持的身份验证方案的优先顺序。
    requestConfigBuilder.setProxyPreferredAuthSchemes();
    //在使用目标主机进行身份验证时,确定受支持的身份验证模式的首选项顺序
    requestConfigBuilder.setTargetPreferredAuthSchemes();
    
    RequestConfig requestConfig = requestConfigBuilder.build();
    httpClientBuilder.setDefaultRequestConfig(requestConfig);

    3. setDefaultSocketConfig()

    HttpClientBuilder httpClientBuilder = HttpClients.custom();
    
    SocketConfig.Builder socketConfigBuilder = SocketConfig.custom();
    //是否立即发送数据,设置为true会关闭Socket缓冲,默认为false
    socketConfigBuilder.setTcpNoDelay(true);
    //是否可以在一个进程关闭Socket后,即使它还没有释放端口,其它进程还可以立即重用端口
    socketConfigBuilder.setSoReuseAddress(true);
    //接收数据的等待超时时间,单位ms
    socketConfigBuilder.setSoTimeout(500);
    //关闭Socket时,要么发送完所有数据,要么等待60s后,就关闭连接,此时socket.close()是阻塞的
    socketConfigBuilder.setSoLinger(60);
    //开启监视TCP连接是否有效
    socketConfigBuilder.setSoKeepAlive(true);
    //backlog, 设置容量限制功能,避免太多的客户端socket占用太多服务器资源。
    socketConfigBuilder.setBacklogSize(100);
    //接收缓冲区
    socketConfigBuilder.setRcvBufSize(8192);
    //发送缓冲区
    socketConfigBuilder.setSndBufSize(8192);
    //决定如果网络上仍然有数据向旧的ServerSocket传输数据,
    //是否允许新的ServerSocket绑定到与旧的ServerSocket同样的端口上。
    //SO_REUSEADDR选项的默认值与操作系统有关,在某些操作系统中,允许重用端口,而在某些操作系统中不允许重用端口。
    socketConfigBuilder.setSoReuseAddress(true);
    
    SocketConfig socketConfig = socketConfigBuilder.build();
    httpClientBuilder.setDefaultSocketConfig(socketConfig);

    4. setConnectionManager()

    HttpClientBuilder httpClientBuilder = HttpClients.custom();
    /**
     * 连接池管理器
     * HttpClientConnectionManager -- 接口
     *      BasicHttpClientConnectionManager -- 实现类, 线程安全
     *      PoolingHttpClientConnectionManager -- 实现类, 线程安全, 一般使用它
     *
     * 1. 当请求一个新的连接时,如果连接池有有可用的持久连接,连接管理器就会使用其中的一个,而不是再创建一个新的连接。
     * PoolingHttpClientConnectionManager维护的连接数在每个路由基础和总数上都有限制。
     * 默认,每个路由基础上的连接不超过2个,总连接数不能超过20。
     * 在实际应用中,这个限制可能会太小了,尤其是当服务器也使用Http协议时。
     *
     * 2. 当使用了请求连接池管理器后,HttpClient就可以同时执行多个线程的请求了。
     * 它会根据配置来分配请求连接。如果连接池中的所有连接都被占用了,那么后续的请求就会被阻塞,
     * 直到有连接被释放回连接池中。为了防止永远阻塞的情况发生,
     * 我们可以把http.conn-manager.timeout的值设置成一个整数。
     * 如果在超时时间内,没有可用连接,就会抛出ConnectionPoolTimeoutException异常。
     *
     * 3. HttpClient的实例是线程安全的,可以被多个线程共享访问,
     * 但是仍旧推荐每个线程都要有自己专用实例的HttpContext。
     * HttpClientContext context = HttpClientContext.create();
     *
     * 4. 连接回收策略
     * 问题:经典阻塞I/O模型的一个主要缺点就是只有当组侧I/O时,socket才能对I/O事件做出反应。
     *      当连接被管理器收回后,这个连接仍然存活,但是却无法监控socket的状态,也无法对I/O事件
     *      做出反馈。如果连接被服务器端关闭了,客户端监测不到连接的状态变化(也就无法根据连接状
     *      态的变化,关闭本地的socket)。
     * HttpClient为了缓解这一问题造成的影响,会在使用某个连接前,监测这个连接是否已经过时,如果
     * 服务器端关闭了连接,那么连接就会失效。这种过时检查并不是100%有效,并且会给每个请求
     * 增加10到30毫秒额外开销。唯一一个可行的,是建立一个监控线程,来专门回收由于长时间不活动
     * 而被判定为失效的连接。这个监控线程可以周期性的调用ClientConnectionManager类
     * (如:PoolingHttpClientConnectionManager)的closeExpiredConnections()方法来关闭过期的连接,
     * 回收连接池中被关闭的连接。它也可以选择性的调用ClientConnectionManager类的
     * closeIdleConnections()方法来关闭一段时间内不活动的连接。
     *
     */
    
    PoolingHttpClientConnectionManager connectionManager = new PoolingHttpClientConnectionManager();
    // 连接池最大的连接数
    connectionManager.setMaxTotal(200);
    // 默认的每个路由上最大的连接数(不能超过连接池总连接数)
    connectionManager.setDefaultMaxPerRoute(20);
    // 每个路由上最大的连接数(不能超过连接池总连接数), 优先于defaultMaxPerRoute
    HttpHost localhost = new HttpHost("https://www.baidu.com/", 80);
    connectionManager.setMaxPerRoute(new HttpRoute(localhost), 50);
    //空闲永久连接检查间隔,这个牵扯的还比较多
    //官方推荐使用这个来检查永久链接的可用性,而不推荐每次请求的时候才去检查(ms)
    connectionManager.setValidateAfterInactivity(1000);
    
    httpClientBuilder.setConnectionManager(connectionManager);

    5. setKeepAliveStrategy()

    HttpClientBuilder httpClientBuilder = HttpClients.custom();
    /**
     * 连接存活策略
     * Http规范没有规定一个持久连接应该保持存活多久。有些Http服务器使用非标准的Keep-Alive头消息
     * 和客户端进行交互,服务器端会保持数秒时间内保持连接。HttpClient也会利用这个头消息。如果
     * 服务器返回的响应中没有包含Keep-Alive头消息,HttpClient会认为这个连接可以永远保持。然而,
     * 很多服务器都会在不通知客户端的情况下,关闭一定时间内不活动的连接,来节省服务器资源。
     * 在某些情况下默认的策略显得太乐观,我们可能需要自定义连接存活策略。
     *
     */
    ConnectionKeepAliveStrategy myStrategy = new ConnectionKeepAliveStrategy() {
    
        public long getKeepAliveDuration(HttpResponse response, HttpContext context) {
            // 接收 'keep-alive' header
            HeaderElementIterator it = new BasicHeaderElementIterator(
                    response.headerIterator(HTTP.CONN_KEEP_ALIVE));
            while (it.hasNext()) {
                HeaderElement he = it.nextElement();
                String param = he.getName();
                String value = he.getValue();
                if (value != null && param.equalsIgnoreCase("timeout")) {
                    try {
                        return Long.parseLong(value) * 1000;
                    } catch(NumberFormatException ignore) {
                    }
                }
            }
            HttpHost target = (HttpHost) context.getAttribute(
                    HttpClientContext.HTTP_TARGET_HOST);
            if ("https://www.baidu.com/".equalsIgnoreCase(target.getHostName())) {
                // Keep alive for 5 seconds only
                return 5 * 1000;
            } else {
                // otherwise keep alive for 30 seconds
                return 30 * 1000;
            }
        }
    };
    
    httpClientBuilder.setKeepAliveStrategy(myStrategy);

    6. setRetryHandler()

    HttpClientBuilder httpClientBuilder = HttpClients.custom();
            
    //禁用重试(参数:retryCount、requestSentRetryEnabled)
    //DefaultHttpRequestRetryHandler不传任何参数, 默认是重试3次
    HttpRequestRetryHandler requestRetryHandler = new DefaultHttpRequestRetryHandler(0, false);
    //自定义重试策略
    HttpRequestRetryHandler myRequestRetryHandler = new HttpRequestRetryHandler() {
        public boolean retryRequest(IOException exception,int executionCount, HttpContext context) {
            //返回true表示重试
            if (executionCount >= 3) {// 如果已经重试了3次,就放弃
                return false;
            }
            if (exception instanceof NoHttpResponseException) {// 如果服务器丢掉了连接,那么就重试
                return true;
            }
            if (exception instanceof SSLHandshakeException) {// 不要重试SSL握手异常
                return false;
            }
            if (exception instanceof InterruptedIOException) {// 超时
                return false;
            }
            if (exception instanceof UnknownHostException) {// 目标服务器不可达
                return false;
            }
            if (exception instanceof ConnectTimeoutException) {// 连接被拒绝
                return false;
            }
            if (exception instanceof SSLException) {// SSL握手异常
                return false;
            }
            return false;
        }
    };
    
    httpClientBuilder.setRetryHandler(myRequestRetryHandler);
  • 相关阅读:
    商品尺码规格和颜色需要支持双引号
    php xss 函数
    yar 调用rpc方法
    【转】Linux常用命令大全
    【Netty】最透彻的Netty原理架构解析
    【Git项目管理】分布式 Git
    【SpringBoot】几种定时任务的实现方式
    【Elasticsearch-Java】Java客户端搭建
    【Git项目管理】Git分支
    【Git项目管理】git新手入门——基础教程
  • 原文地址:https://www.cnblogs.com/myitnews/p/12195340.html
Copyright © 2020-2023  润新知