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

被折叠的 条评论
为什么被折叠?



