背景
- 接口类型: HTTPS
- 工具类:
org.apache.http.impl.client
发现网络上找到的许多信息并不真确,无法真正地完成 HTTPS 接口的请求,经过测试,写出如下示例代码。
要点
代码示例
以下方法,均可同时支持 HTTP 和 HTTPS
法一
import org.apache.http.config.Registry;
import org.apache.http.config.RegistryBuilder;
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.TrustSelfSignedStrategy;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
import org.apache.http.ssl.SSLContextBuilder;
import javax.net.ssl.SSLContext;
import java.security.KeyManagementException;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
public class HttpsClient {
public CloseableHttpClient getCloseableHttpsClient() throws NoSuchAlgorithmException, KeyStoreException, KeyManagementException {
SSLContextBuilder builder = new SSLContextBuilder()
.loadTrustMaterial(null, new TrustSelfSignedStrategy())
.setSecureRandom(null)
.useProtocol("TLSv1.3");
SSLContext sslContext = builder.build();
SSLConnectionSocketFactory sslConnectionSocketFactory = new SSLConnectionSocketFactory(
sslContext, null, null, new NoopHostnameVerifier()
);
Registry<ConnectionSocketFactory> registry = RegistryBuilder.
<ConnectionSocketFactory> create()
.register("http", new PlainConnectionSocketFactory())
.register("https", sslConnectionSocketFactory)
.build();
PoolingHttpClientConnectionManager cm = new PoolingHttpClientConnectionManager(registry);
cm.setMaxTotal(2000);
CloseableHttpClient httpClient = HttpClients.custom()
.setSSLSocketFactory(sslConnectionSocketFactory)
.setConnectionManager(cm)
.build();
return httpClient;
}
}
法二
import org.apache.http.HttpEntity;
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.config.Registry;
import org.apache.http.config.RegistryBuilder;
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.HttpClients;
import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
import org.apache.http.util.EntityUtils;
import org.junit.Test;
import org.springframework.boot.test.context.SpringBootTest;
import javax.net.ssl.SSLContext;
import javax.net.ssl.TrustManager;
import javax.net.ssl.X509TrustManager;
import java.io.IOException;
import java.security.KeyManagementException;
import java.security.NoSuchAlgorithmException;
import java.security.cert.CertificateException;
@SpringBootTest
public class HttpsClientTest2 {
public static SSLContext createIgnoreVerifySSLContext() {
SSLContext sslContext = null;
try {
sslContext = SSLContext.getInstance("TLSv1.3");
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
}
X509TrustManager trustManager = new X509TrustManager() {
@Override
public void checkClientTrusted(java.security.cert.X509Certificate[] paramArrayOfX509Certificate,
String paramString) throws CertificateException {
}
@Override
public void checkServerTrusted(java.security.cert.X509Certificate[] paramArrayOfX509Certificate,
String paramString) throws CertificateException {
}
@Override
public java.security.cert.X509Certificate[] getAcceptedIssuers() {
return null;
}
};
try {
sslContext.init(null, new TrustManager[] { trustManager }, null);
} catch (KeyManagementException e) {
e.printStackTrace();
}
return sslContext;
}
public static CloseableHttpClient getCloseableHttpsClient() {
SSLContext sslcontext = createIgnoreVerifySSLContext();
Registry<ConnectionSocketFactory> socketFactoryRegistry = RegistryBuilder.<ConnectionSocketFactory> create()
.register("http", PlainConnectionSocketFactory.INSTANCE)
.register("https", new SSLConnectionSocketFactory(sslcontext))
.build();
PoolingHttpClientConnectionManager connManager = new PoolingHttpClientConnectionManager(socketFactoryRegistry);
CloseableHttpClient client = HttpClients.custom()
.setConnectionManager(connManager)
.build();
return client;
}
}
测试
public void httpsSupportTest() throws Exception {
CloseableHttpClient httpClient = getCloseableHttpsClient();
CloseableHttpResponse response = null;
String result = "";
String urlHttps = "https://my-https-url";
String secretKeyHttps = "my-secret-key";
HttpGet getRequest_1 = new HttpGet(urlHttps);
getRequest_1.setHeader("secretKey", secretKeyHttps);
RequestConfig requestConfig = RequestConfig.custom()
.setConnectTimeout(120000)
.setConnectionRequestTimeout(120000)
.setSocketTimeout(120000)
.setRedirectsEnabled(true).build();
getRequest_1.setConfig(requestConfig);
try {
response = httpClient.execute(getRequest_1);
HttpEntity responseEntity = response.getEntity();
if (responseEntity != null) {
result = EntityUtils.toString(responseEntity);
System.out.println("result: " + result);
}
} catch (IOException e) {
e.printStackTrace();
}
}
备注:
- 以上方法,本质上是忽略了安全证书的校验,违背了 HTTPS 的使用初衷,不建议用到生产中。
- 如果出现提示
TLSv1.3 is not supported 不支持的报错,请检查 JDK 的版本,因为 TLSv1.3 对 JDK 的小版本有要求(参考4)
参考
- https://zhuanlan.zhihu.com/p/86980940
- https://github.com/apache/httpcomponents-client/blob/5.1.x/httpclient5/src/test/java/org/apache/hc/client5/http/examples/ClientCustomSSL.java
- https://stackoverflow.com/questions/19517538/ignoring-ssl-certificate-in-apache-httpclient-4-3
- http://openjdk.java.net/jeps/332
|