HttpClient工具常用配置
常用配置项
import okhttp3.*; import okhttp3.internal.Util; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import javax.net.ssl.SSLContext; import javax.net.ssl.SSLSocketFactory; import javax.net.ssl.TrustManager; import java.io.File; import java.io.IOException; import java.security.SecureRandom; import java.util.concurrent.ExecutorService; import java.util.concurrent.SynchronousQueue; import java.util.concurrent.ThreadPoolExecutor; import java.util.concurrent.TimeUnit; /** * OkHttpUtil * * @author liuxing * @summary OkHttpUtil * @since 2017-11-10 17:42 */ public class OkHttpUtil { private static final Logger LOGGER = LoggerFactory.getLogger(OkHttpUtil.class); public static OkHttpClient client; static { OkHttpClient.Builder build = new OkHttpClient.Builder() // 失败后重试,默认true .retryOnConnectionFailure(true) // 读取超时 默认 10秒 .readTimeout(10, TimeUnit.SECONDS) // 写入超时 默认 10秒 .writeTimeout(10, TimeUnit.SECONDS) // 连接超时 默认 10秒 .connectTimeout(5, TimeUnit.SECONDS) // 连接池 默认是ConnectionPool的构造设置 .connectionPool(new ConnectionPool(100, 30, TimeUnit.SECONDS)) // 心跳时间 默认0,不检测 .pingInterval(5, TimeUnit.SECONDS); ExecutorService executor = new ThreadPoolExecutor(50, 200, 30, TimeUnit.SECONDS, new SynchronousQueue<>(), Util.threadFactory("OkHttp Dispatcher", false)); // 异步调度线程池 Dispatcher dispatcher = new Dispatcher(executor); dispatcher.setMaxRequests(1000); dispatcher.setMaxRequestsPerHost(1000); build.dispatcher(dispatcher); // ssl build.sslSocketFactory(createSSLSocketFactory(), new TrustAllManager()); build.hostnameVerifier(new TrustAllHostnameVerifier()); client = build.build(); } public static OkHttpClient client() { return client; } /** * 默认信任所有的证书 * TODO 最好加上证书认证,主流App都有自己的证书 * * @return */ private static SSLSocketFactory createSSLSocketFactory() { SSLSocketFactory sSLSocketFactory = null; try { SSLContext sc = SSLContext.getInstance("TLS"); sc.init(null, new TrustManager[]{new TrustAllManager()}, new SecureRandom()); sSLSocketFactory = sc.getSocketFactory(); } catch (Exception e) { } return sSLSocketFactory; } }
常用配置项
import org.apache.http.client.ClientProtocolException; import org.apache.http.client.config.RequestConfig; 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.conn.ssl.TrustStrategy; import org.apache.http.entity.ContentType; import org.apache.http.entity.InputStreamEntity; import org.apache.http.impl.client.*; import org.apache.http.ssl.SSLContexts; import org.apache.http.util.EntityUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import javax.net.ssl.SSLContext; import javax.net.ssl.TrustManager; import javax.net.ssl.X509TrustManager; import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.IOException; import java.security.SecureRandom; import java.security.cert.CertificateException; import java.security.cert.X509Certificate; import java.util.concurrent.TimeUnit; /** * HttpClientUtil * * @author liuxing * @summary HttpClientUtil * @since 2017-12-01 14:43 */ public class HttpClientUtil { private static final Logger LOGGER = LoggerFactory.getLogger(HttpClientUtil.class); private static CloseableHttpClient httpClient; static { HttpClientBuilder builder = HttpClients.custom(); builder.setConnectionTimeToLive(30L, TimeUnit.SECONDS); builder.setMaxConnTotal(1000); builder.setMaxConnPerRoute(1000); builder.setRetryHandler(new DefaultHttpRequestRetryHandler(2, true)); // 保持长连接配置,需要在头添加Keep-Alive // 该策略依赖响应头的Keep-Alive参数:如 Keep-Alive: timeout=5, max=100 单位秒 // 否则则依赖ConnectionTimeToLive的设置 builder.setKeepAliveStrategy(DefaultConnectionKeepAliveStrategy.INSTANCE); try { SSLContext sslContext = SSLContexts.custom().loadTrustMaterial(null, (TrustStrategy) (chain, authType) -> true).build(); builder.setSSLContext(sslContext); } catch (Exception e) { LOGGER.error(e.getMessage(), e); } try { SSLContext sc = SSLContext.getInstance("TLS"); sc.init(null, new TrustManager[]{new TrustAllManager()}, new SecureRandom()); builder.setSSLContext(sc); } catch (Exception e) { LOGGER.error(e.getMessage(), e); } RequestConfig requestConfig = RequestConfig.custom() // 读写超时 .setSocketTimeout(10000) // 请求超时 .setConnectTimeout(10000) // 从连接池中获取连接的时间,非请求时间 .setConnectionRequestTimeout(200) // 最大重定向次数 .setMaxRedirects(10) // 自动gzip .setContentCompressionEnabled(true) .build(); builder.setDefaultRequestConfig(requestConfig); httpClient = builder.build(); LOGGER.info("requestConfig: {}", requestConfig.toString()); } public static CloseableHttpClient client() { return httpClient; } /** * 信任所有证书 * * @author liuxing * @summary 信任所有证书 * @since 2017-11-30 23:36 */ public static class TrustAllManager implements X509TrustManager { @Override public void checkClientTrusted(X509Certificate[] chain, String authType) throws CertificateException { } @Override public void checkServerTrusted(X509Certificate[] chain, String authType) throws CertificateException { } @Override public X509Certificate[] getAcceptedIssuers() { return new X509Certificate[0]; } } }
RestTemplate本质只是一个模板,具体的请求需要根据初始化配置的RequestFactory
从Spring 4.3.x开始,可以选择OkHttp、HttpClient、Netty
默认是使用Java URLConnection(未池化连接,不推荐使用)。
HttpClient、OkHttp、RestTemplate都只需要配置一个全局单例即可。
常用的超时时间配置5-10秒即可,最大并发连接500-1000,都默认开启的Gzip压缩
以HttpClient为例
<dependency> <groupId>org.apache.httpcomponents</groupId> <artifactId>httpclient</artifactId> <version>4.5.4</version> </dependency> <dependency> <groupId>org.apache.httpcomponents</groupId> <artifactId>httpmime</artifactId> <version>4.5.4</version> </dependency>
/** * 普通的get请求 */ @Test public void testDoGet() { HttpGet httpGet = new HttpGet("https://www.baidu.com"); try { try (CloseableHttpResponse response = client.execute(httpGet)) { if (Objects.equals(response.getStatusLine().getStatusCode(), HttpStatus.SC_OK)) { LOGGER.info("GET 请求成功:/n {}", EntityUtils.toString(response.getEntity())); } else { LOGGER.error("GET 请求失败:/n {}", EntityUtils.toString(response.getEntity())); } } } catch (Exception e) { LOGGER.error(e.getMessage(), e); } finally { httpGet.releaseConnection(); } }
/** * 普通的表单请求 */ @Test public void testDoPost() { HttpPost httpPost = new HttpPost("http://localhost:3000/api"); HttpEntity entity = EntityBuilder.create() .setParameters( new BasicNameValuePair("errFlag", "false"), new BasicNameValuePair("name", "xxx"), new BasicNameValuePair("code", "123456") ) .setContentType(ContentType.create("application/x-www-form-urlencoded", "utf-8")) .build(); httpPost.setEntity(entity); try { try (CloseableHttpResponse response = client.execute(httpPost)) { if (Objects.equals(response.getStatusLine().getStatusCode(), HttpStatus.SC_OK)) { LOGGER.info("POST 请求成功:/n {}", EntityUtils.toString(response.getEntity())); } else { LOGGER.error("POST 请求失败:/n {}", EntityUtils.toString(response.getEntity())); } } } catch (Exception e) { LOGGER.error(e.getMessage(), e); } finally { httpPost.releaseConnection(); } }
/** * json数据post请求 * <p> * put、delete、patch同post * 使用不同的method实现 @see {@link org.apache.http.client.methods.HttpEntityEnclosingRequestBase} */ @Test public void testDoJsonPost() { Map<String, Object> params = new HashMap<>(); params.put("name", "xxx"); params.put("code", "123456"); params.put("errFlag", "false"); HttpPost httpPost = new HttpPost("http://localhost:3000/api"); HttpEntity entity = EntityBuilder.create() .setText(JSON.toJSONString(params)) .setContentType(ContentType.create("application/json", "utf-8")) .build(); httpPost.setEntity(entity); try { try (CloseableHttpResponse response = client.execute(httpPost)) { if (Objects.equals(response.getStatusLine().getStatusCode(), HttpStatus.SC_OK)) { LOGGER.info("POST JSON 请求成功:/n {}", EntityUtils.toString(response.getEntity())); } else { LOGGER.error("POST JSON 请求失败:/n {}", EntityUtils.toString(response.getEntity())); } } } catch (Exception e) { LOGGER.error(e.getMessage(), e); } finally { httpPost.releaseConnection(); } }