mirror of
https://gitee.com/chinabugotech/hutool.git
synced 2025-07-21 15:09:48 +08:00
fix http
This commit is contained in:
@@ -1,5 +1,16 @@
|
||||
package cn.hutool.http;
|
||||
|
||||
import cn.hutool.core.map.MapUtil;
|
||||
import cn.hutool.core.util.ObjectUtil;
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import cn.hutool.core.util.URLUtil;
|
||||
import cn.hutool.http.ssl.AndroidSupportSSLFactory;
|
||||
import cn.hutool.http.ssl.DefaultSSLInfo;
|
||||
import cn.hutool.http.ssl.SSLSocketFactoryBuilder;
|
||||
|
||||
import javax.net.ssl.HostnameVerifier;
|
||||
import javax.net.ssl.HttpsURLConnection;
|
||||
import javax.net.ssl.SSLSocketFactory;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
@@ -16,17 +27,6 @@ import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
|
||||
import javax.net.ssl.HostnameVerifier;
|
||||
import javax.net.ssl.HttpsURLConnection;
|
||||
import javax.net.ssl.SSLSocketFactory;
|
||||
|
||||
import cn.hutool.core.map.MapUtil;
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import cn.hutool.core.util.URLUtil;
|
||||
import cn.hutool.http.ssl.AndroidSupportSSLFactory;
|
||||
import cn.hutool.http.ssl.SSLSocketFactoryBuilder;
|
||||
import cn.hutool.http.ssl.TrustAnyHostnameVerifier;
|
||||
|
||||
/**
|
||||
* http连接对象,对HttpURLConnection的包装
|
||||
*
|
||||
@@ -262,20 +262,8 @@ public class HttpConnection {
|
||||
// Https请求
|
||||
final HttpsURLConnection httpsConn = (HttpsURLConnection) conn;
|
||||
// 验证域
|
||||
httpsConn.setHostnameVerifier(null != hostnameVerifier ? hostnameVerifier : new TrustAnyHostnameVerifier());
|
||||
if (null == ssf) {
|
||||
try {
|
||||
if (StrUtil.equalsIgnoreCase("dalvik", System.getProperty("java.vm.name"))) {
|
||||
// 兼容android低版本SSL连接
|
||||
ssf = new AndroidSupportSSLFactory();
|
||||
} else {
|
||||
ssf = SSLSocketFactoryBuilder.create().build();
|
||||
}
|
||||
} catch (KeyManagementException | NoSuchAlgorithmException e) {
|
||||
throw new HttpException(e);
|
||||
}
|
||||
}
|
||||
httpsConn.setSSLSocketFactory(ssf);
|
||||
httpsConn.setHostnameVerifier(ObjectUtil.defaultIfNull(hostnameVerifier, DefaultSSLInfo.TRUST_ANY_HOSTNAME_VERIFIER));
|
||||
httpsConn.setSSLSocketFactory(ObjectUtil.defaultIfNull(ssf, DefaultSSLInfo.DEFAULT_SSF));
|
||||
}
|
||||
|
||||
return this;
|
||||
|
@@ -857,12 +857,11 @@ public class HttpRequest extends HttpBase<HttpRequest> {
|
||||
* @see #setSSLSocketFactory(SSLSocketFactory)
|
||||
*/
|
||||
public HttpRequest setSSLProtocol(String protocol) {
|
||||
if (null == this.ssf) {
|
||||
try {
|
||||
this.ssf = SSLSocketFactoryBuilder.create().setProtocol(protocol).build();
|
||||
} catch (Exception e) {
|
||||
throw new HttpException(e);
|
||||
}
|
||||
Assert.notBlank(protocol, "protocol must be not blank!");
|
||||
try {
|
||||
this.ssf = SSLSocketFactoryBuilder.create().setProtocol(protocol).build();
|
||||
} catch (Exception e) {
|
||||
throw new HttpException(e);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
@@ -930,13 +929,13 @@ public class HttpRequest extends HttpBase<HttpRequest> {
|
||||
this.url = HttpUtil.encodeParams(this.url, this.charset);
|
||||
}
|
||||
// 初始化 connection
|
||||
initConnecton();
|
||||
initConnection();
|
||||
|
||||
// 发送请求
|
||||
send();
|
||||
|
||||
// 手动实现重定向
|
||||
HttpResponse httpResponse = sendRedirectIfPosible();
|
||||
HttpResponse httpResponse = sendRedirectIfPossible();
|
||||
|
||||
// 获取响应
|
||||
if (null == httpResponse) {
|
||||
@@ -966,7 +965,7 @@ public class HttpRequest extends HttpBase<HttpRequest> {
|
||||
/**
|
||||
* 初始化网络连接
|
||||
*/
|
||||
private void initConnecton() {
|
||||
private void initConnection() {
|
||||
if (null != this.httpConnection) {
|
||||
// 执行下次请求时自动关闭上次请求(常用于转发)
|
||||
this.httpConnection.disconnectQuietly();
|
||||
@@ -1018,7 +1017,7 @@ public class HttpRequest extends HttpBase<HttpRequest> {
|
||||
*
|
||||
* @return {@link HttpResponse},无转发返回 <code>null</code>
|
||||
*/
|
||||
private HttpResponse sendRedirectIfPosible() {
|
||||
private HttpResponse sendRedirectIfPossible() {
|
||||
if (this.maxRedirectCount < 1) {
|
||||
// 不重定向
|
||||
return null;
|
||||
|
@@ -1,5 +1,7 @@
|
||||
package cn.hutool.http.ssl;
|
||||
|
||||
import cn.hutool.core.util.ArrayUtil;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.InetAddress;
|
||||
import java.net.Socket;
|
||||
@@ -13,7 +15,6 @@ import javax.net.ssl.SSLSocketFactory;
|
||||
* 自定义支持协议类型的SSLSocketFactory
|
||||
*
|
||||
* @author looly
|
||||
*
|
||||
*/
|
||||
public class CustomProtocolsSSLFactory extends SSLSocketFactory {
|
||||
|
||||
@@ -45,45 +46,42 @@ public class CustomProtocolsSSLFactory extends SSLSocketFactory {
|
||||
|
||||
@Override
|
||||
public Socket createSocket() throws IOException {
|
||||
SSLSocket sslSocket = (SSLSocket) base.createSocket();
|
||||
final SSLSocket sslSocket = (SSLSocket) base.createSocket();
|
||||
resetProtocols(sslSocket);
|
||||
return sslSocket;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SSLSocket createSocket(Socket s, String host, int port, boolean autoClose) throws IOException {
|
||||
SSLSocket socket = (SSLSocket) base.createSocket(s, host, port, autoClose);
|
||||
final SSLSocket socket = (SSLSocket) base.createSocket(s, host, port, autoClose);
|
||||
resetProtocols(socket);
|
||||
return socket;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Socket createSocket(String host, int port) throws IOException {
|
||||
SSLSocket socket = (SSLSocket) base.createSocket(host, port);
|
||||
final SSLSocket socket = (SSLSocket) base.createSocket(host, port);
|
||||
resetProtocols(socket);
|
||||
return socket;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Socket createSocket(String host, int port, InetAddress localHost, int localPort) throws IOException {
|
||||
|
||||
SSLSocket socket = (SSLSocket) base.createSocket(host, port, localHost, localPort);
|
||||
final SSLSocket socket = (SSLSocket) base.createSocket(host, port, localHost, localPort);
|
||||
resetProtocols(socket);
|
||||
return socket;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Socket createSocket(InetAddress host, int port) throws IOException {
|
||||
|
||||
SSLSocket socket = (SSLSocket) base.createSocket(host, port);
|
||||
final SSLSocket socket = (SSLSocket) base.createSocket(host, port);
|
||||
resetProtocols(socket);
|
||||
return socket;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Socket createSocket(InetAddress address, int port, InetAddress localAddress, int localPort) throws IOException {
|
||||
|
||||
SSLSocket socket = (SSLSocket) base.createSocket(address, port, localAddress, localPort);
|
||||
final SSLSocket socket = (SSLSocket) base.createSocket(address, port, localAddress, localPort);
|
||||
resetProtocols(socket);
|
||||
return socket;
|
||||
}
|
||||
@@ -94,7 +92,9 @@ public class CustomProtocolsSSLFactory extends SSLSocketFactory {
|
||||
* @param socket SSLSocket
|
||||
*/
|
||||
private void resetProtocols(SSLSocket socket) {
|
||||
socket.setEnabledProtocols(protocols);
|
||||
if(ArrayUtil.isNotEmpty(this.protocols)){
|
||||
socket.setEnabledProtocols(this.protocols);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@@ -0,0 +1,18 @@
|
||||
package cn.hutool.http.ssl;
|
||||
|
||||
import java.security.KeyManagementException;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
|
||||
/**
|
||||
* 默认的SSLSocketFactory
|
||||
*
|
||||
* @author Looly
|
||||
* @since 5.1.2
|
||||
*/
|
||||
public class DefaultSSLFactory extends CustomProtocolsSSLFactory {
|
||||
|
||||
public DefaultSSLFactory() throws KeyManagementException, NoSuchAlgorithmException {
|
||||
super();
|
||||
}
|
||||
|
||||
}
|
@@ -0,0 +1,40 @@
|
||||
package cn.hutool.http.ssl;
|
||||
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import cn.hutool.http.HttpException;
|
||||
|
||||
import javax.net.ssl.SSLSocketFactory;
|
||||
import java.security.KeyManagementException;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
|
||||
/**
|
||||
* 默认的SSL配置,当用户未设置相关信息时,使用默认设置,默认设置为单例模式。
|
||||
*
|
||||
* @author looly
|
||||
* @since 5.1.2
|
||||
*/
|
||||
public class DefaultSSLInfo {
|
||||
/**
|
||||
* 默认信任全部的域名校验器
|
||||
*/
|
||||
public static final TrustAnyHostnameVerifier TRUST_ANY_HOSTNAME_VERIFIER;
|
||||
/**
|
||||
* 默认的SSLSocketFactory,区分安卓
|
||||
*/
|
||||
public static final SSLSocketFactory DEFAULT_SSF;
|
||||
|
||||
static {
|
||||
TRUST_ANY_HOSTNAME_VERIFIER = new TrustAnyHostnameVerifier();
|
||||
|
||||
try {
|
||||
if (StrUtil.equalsIgnoreCase("dalvik", System.getProperty("java.vm.name"))) {
|
||||
// 兼容android低版本SSL连接
|
||||
DEFAULT_SSF = new AndroidSupportSSLFactory();
|
||||
} else {
|
||||
DEFAULT_SSF = new DefaultSSLFactory();
|
||||
}
|
||||
} catch (KeyManagementException | NoSuchAlgorithmException e) {
|
||||
throw new HttpException(e);
|
||||
}
|
||||
}
|
||||
}
|
@@ -7,8 +7,8 @@ import javax.net.ssl.X509TrustManager;
|
||||
|
||||
/**
|
||||
* 证书管理
|
||||
* @author Looly
|
||||
*
|
||||
* @author Looly
|
||||
*/
|
||||
public class DefaultTrustManager implements X509TrustManager {
|
||||
|
||||
@@ -18,10 +18,10 @@ public class DefaultTrustManager implements X509TrustManager {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void checkClientTrusted(X509Certificate[] chain, String authType) throws CertificateException {
|
||||
public void checkClientTrusted(X509Certificate[] chain, String authType) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void checkServerTrusted(X509Certificate[] chain, String authType) throws CertificateException {
|
||||
public void checkServerTrusted(X509Certificate[] chain, String authType) {
|
||||
}
|
||||
}
|
||||
|
28
hutool-http/src/test/java/cn/hutool/http/test/HttpsTest.java
Normal file
28
hutool-http/src/test/java/cn/hutool/http/test/HttpsTest.java
Normal file
@@ -0,0 +1,28 @@
|
||||
package cn.hutool.http.test;
|
||||
|
||||
import cn.hutool.core.lang.Console;
|
||||
import cn.hutool.core.thread.ThreadUtil;
|
||||
import cn.hutool.http.HttpUtil;
|
||||
import org.junit.Ignore;
|
||||
import org.junit.Test;
|
||||
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
|
||||
public class HttpsTest {
|
||||
|
||||
/**
|
||||
* 测试单例的SSLSocketFactory是否有线程安全问题
|
||||
*/
|
||||
@Test
|
||||
@Ignore
|
||||
public void getTest() {
|
||||
final AtomicInteger count = new AtomicInteger();
|
||||
for(int i =0; i < 100; i++){
|
||||
ThreadUtil.execute(()->{
|
||||
final String s = HttpUtil.get("https://www.baidu.com/");
|
||||
Console.log(count.incrementAndGet());
|
||||
});
|
||||
}
|
||||
ThreadUtil.sync(this);
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user