Java中httpclient的单例工厂类示例

本文介绍了在Java中使用Apache HttpClient和OkHttp创建http请求时,如何设计和实现httpclient的单例工厂类,以进行项目中统一的配置管理。示例代码详细展示了两种方式的配置,包括常见参数的设置。建议根据项目需求调整配置,并可查阅HttpClient 4.5.x和OkHttp 3.12.x官方文档深入学习。

        在 Java 中经常会有要发送 http 请求并解析响应的场景,此时用的最多的两个类库分别是 Apache 的 HttpClient 类库和 OkHttp 的 OkHttpClient 类库。在使用这两个类库的时候,一般都会先创建 httpclient 的单例工厂类,定义项目中对于 httpclient 的默认配置。

        HttpClient 类库的单例工厂类示例:

package com.frank.test.util;

import java.nio.charset.StandardCharsets;
import java.security.KeyManagementException;
import java.security.NoSuchAlgorithmException;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;

import javax.net.ssl.SSLContext;
import javax.net.ssl.TrustManager;
import javax.net.ssl.X509TrustManager;

import org.apache.commons.io.IOUtils;
import org.apache.http.HttpRequest;
import org.apache.http.HttpResponse;
import org.apache.http.ProtocolException;
import org.apache.http.client.RedirectStrategy;
import org.apache.http.client.ServiceUnavailableRetryStrategy;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.methods.HttpUriRequest;
import org.apache.http.config.ConnectionConfig;
import org.apache.http.config.Registry;
import org.apache.http.config.RegistryBuilder;
import org.apache.http.config.SocketConfig;
import org.apache.http.conn.socket.ConnectionSocketFactory;
import org.apache.http.conn.socket.PlainConnectionSocketFactory;
import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.DefaultHttpRequestRetryHandler;
import org.apache.http.impl.client.HttpClientBuilder;
import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
import org.apache.http.protocol.HttpContext;

/**
 * Apache 的 httpclient 的工厂类。
 * 
 * @author 
 * @date 
 */
public final class HttpClientFactory {
    private HttpClientFactory() {}
    
    private static CloseableHttpClient _INSTANCE = null;
    
    static {
        /*********************************************** ConnectionManager start *****************************************/
        // 设置协议http和https对应的处理socket连接工厂的对象
        Registry<ConnectionSocketFactory> socketFactoryRegistry = RegistryBuilder.<ConnectionSocketFactory>create()
                .register("http", PlainConnectionSocketFactory.getSocketFactory())
                .register("https", new SSLConnectionSocketFactory(createIgnoreVerifySSL()))
                .build();
        PoolingHttpClientConnectionManager connManager = new PoolingHttpClientConnectionManager(socketFactoryRegistry);
        ConnectionConfig defaultConnectionConfig = ConnectionConfig.custom()
//                .setBufferSize(10 * 1024)// 设置为10K,默认是 8 * 1024
                .setCharset(StandardCharsets.UTF_8)
                .build();
        SocketConfig defaultSocketConfig = SocketConfig.custom()
                .setSoTimeout(2000)// socket 超时,单位:ms。默认是 0
//                .setTcpNoDelay(true)// 默认是 true
//                .setSoKeepAlive(false)// 默认是 false
                .build();
        connManager.setDefaultConnectionConfig(defaultConnectionConfig);
        connManager.setDefaultMaxPerRoute(3);
        connManager.setDefaultSocketConfig(defaultSocketConfig);
        connManager.setMaxTotal(100);
        connManager.setValidateAfterInactivity(-1);// 对于 HTTP 连接,一般情况不需要验证
        /*********************************************** ConnectionManager end *****************************************/
        
        // 响应码是 503 时,不再进行重试
        ServiceUnavailableRetryStrategy noRetry503Strategy = new ServiceUnavailableRetryStrategy() {
            @Override
            public boolean retryRequest(HttpResponse response, int executionCount, HttpContext context) {
                return false;
            }
            @Override
            public long getRetryInterval() {
                return -1;
            }
        };
        // 不处理重定向的状态码
        RedirectStrategy noRedirectStrategy = new RedirectStrategy() {
            @Override
            public boolean isRedirected(HttpRequest request, HttpResponse response, HttpContext context) throws ProtocolException {
                return false;
            }
            @Override
            public HttpUriRequest getRedirect(HttpRequest request, HttpResponse response, HttpContext context) throws ProtocolException {
                return null;
            }
        };
        RequestConfig defaultRequestConfig = RequestConfig.custom()
                .setRedirectsEnabled(false)// 不启用重定向
                .setConnectionRequestTimeout(1000)// 从 ConnectionManager 中获取请求的最大超时时间,单位:ms
                .setConnectTimeout(2000)// 连接超时,此处设置为一个相对较大的值,因为也可以在单个请求里控制 RequestConfig,单位:ms
                .setSocketTimeout(2000)// socket 超时,和 SocketConfig 中保持一致,单位:ms
                .setContentCompressionEnabled(true)// 启用压缩
                .build();
        _INSTANCE = HttpClientBuilder.create()
                .setConnectionManager(connManager)
                .setRetryHandler(new DefaultHttpRequestRetryHandler(0, false))// 不进行请求重发
                .setServiceUnavailableRetryStrategy(noRetry503Strategy)
//                .setDefaultHeaders(defaultHeaders)// 默认头
                .setDefaultRequestConfig(defaultRequestConfig)
                .setRedirectStrategy(noRedirectStrategy)
                .build();
    }
    
    private static SSLContext createIgnoreVerifySSL() {
        try {
            SSLContext sc = SSLContext.getInstance("SSLv3");
            
            // 实现一个X509TrustManager接口,用于绕过验证
            X509TrustManager trustManager = new X509TrustManager() {
                @Override
                public X509Certificate[] getAcceptedIssuers() {
                    return null;
                }
                @Override
                public void checkServerTrusted(X509Certificate[] chain, String authType) throws CertificateException {}
                @Override
                public void checkClientTrusted(X509Certificate[] chain, String authType) throws CertificateException {}
            };
            
            sc.init(null, new TrustManager[] { trustManager }, null);
            return sc;
        } catch (NoSuchAlgorithmException | KeyManagementException e) {
            return null;
        }
    }
    
    /**
     * 获取 CloseableHttpClient
     * 
     * @return
     */
    public static CloseableHttpClient getHttpClient() {
        return _INSTANCE;
    }
    
    /**
     * 关闭 CloseableHttpClient 并释放资源。
     */
    @SuppressWarnings({ "deprecation" })
    public static void close() {
        IOUtils.closeQuietly((PoolingHttpClientConnectionManager) _INSTANCE.getConnectionManager(), _INSTANCE);
    }
}

        OkHttpClient 类库的单例工厂类示例:

package com.frank.test.util;

import java.security.KeyManagementException;
import java.security.NoSuchAlgorithmException;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
import java.util.concurrent.TimeUnit;

import javax.net.ssl.SSLContext;
import javax.net.ssl.TrustManager;
import javax.net.ssl.X509TrustManager;

import okhttp3.ConnectionPool;
import okhttp3.OkHttpClient;

/**
 * OkHttpClient 的工具类。
 * 
 * @author 
 * @date 
 */
public final class OkHttpClientFactory {
    private OkHttpClientFactory() {}
    
    private static OkHttpClient _INSTANCE = null;
    static {
        X509TrustManager trustAllManager = new X509TrustManager() {
            @Override
            public X509Certificate[] getAcceptedIssuers() {
                return new X509Certificate[] {};
            }
            @Override
            public void checkServerTrusted(X509Certificate[] chain, String authType) throws CertificateException {}
            @Override
            public void checkClientTrusted(X509Certificate[] chain, String authType) throws CertificateException {}
        };
        
        _INSTANCE = new OkHttpClient.Builder()
            .connectionPool(new ConnectionPool(3, 1, TimeUnit.MINUTES))
            .followRedirects(false)// 不进行重定向
            .followSslRedirects(true)
            .retryOnConnectionFailure(false)// 连接失败后不重试
            .connectTimeout(2, TimeUnit.SECONDS)// 连接超时,此处设置为一个相对较大的值,因为也可以在单个请求里控制
            .readTimeout(2, TimeUnit.SECONDS)// 读取超时
            .writeTimeout(2, TimeUnit.SECONDS)// 写超时
            // 整个HTTP请求的超时时间,包含:resolving DNS, connecting, writing the request body, server processing, and reading the response body
            .callTimeout(6, TimeUnit.SECONDS)
            // 支持ssl并忽略ssl认证
            .sslSocketFactory(createIgnoreVerifySSL(trustAllManager).getSocketFactory(), trustAllManager)
            .build();
    }
    
    private static SSLContext createIgnoreVerifySSL(X509TrustManager trustManager) {
        try {
            SSLContext sc = SSLContext.getInstance("TLS");
            sc.init(null, new TrustManager[] { trustManager }, null);
            return sc;
        } catch (NoSuchAlgorithmException | KeyManagementException e) {
            return null;
        }
    }
    
    /**
     * 获取 OkHttpClient
     * 
     * @return
     */
    public static OkHttpClient getHttpClient() {
        return _INSTANCE;
    }
    
    /**
     * 关闭 OkHttpClient 并释放资源。
     */
    public static void close() {
        _INSTANCE.dispatcher().executorService().shutdown();
        _INSTANCE.connectionPool().evictAll();
    }
}

        两个示例中,都给出了大多数参数的配置。在真正使用的时候,可以根据自己项目的需求修改这些值。如果想了解这两个的类库的全部功能,可以参看官方文档:HttpClient 4.5.xOkHttp 3.12.x​​​​​​​。

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值