使用 https URL、HttpsURL 连接有效,但 HttpClient 无效
With https URL, HttpsURLConnection works but HttpClient does not
我有一个网络应用程序(在 WebSphere 上)与第 3 方交互以格式化一些接收到的数据,然后 RESTful 调用驻留在 Tomcat server
上的第 3 方。在 Web 应用程序中,我可以使用 Java 的原生 HttpsUrlConnection
(见下文)成功进行基本的 RESTful GET
调用,但是当我使用 Apache 的 HttpClient
,它因 SSL
链接错误而失败。
HttpsURLConnection:
String urlWithParams = "https://example.com/rest/issue/59";
String methodType = "GET";
String acceptType = MediaType.APPLICATION_JSON;
HttpsURLConnection conn = null;
try {
URL url = new URL(urlWithParams);
conn = (HttpsURLConnection) url.openConnection();
conn.setRequestMethod(methodType);
conn.setRequestProperty("Accept", acceptType);
if (conn.getResponseCode() != 200) {
System.out.println("Failed. httpErrorUrl=" + conn.getResponseCode()
+ " httpErrorCode=" + conn.getResponseCode()
+ " httpErrorMsg=" + conn.getResponseMessage());
}
BufferedReader br = new BufferedReader(new InputStreamReader((conn.getInputStream())));
String rawData;
String toReturn = "";
while ((rawData = br.readLine()) != null) {
toReturn += rawData;
}
System.out.println(toReturn);
} catch (MalformedURLException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally{
if(conn != null){
conn.disconnect();
} else {
System.out.println("httpUrlConnection is null");
}
}
HttpClient代码:
String uri = "https://example.com/rest/issue/59";
PoolingHttpClientConnectionManager connManager = new PoolingHttpClientConnectionManager();
connManager.setDefaultMaxPerRoute(20);
connManager.setMaxTotal(40);
CloseableHttpClient httpclient = HttpClients.createDefault();
HttpClient 方法在以下函数中执行:
private JSON request(HttpRequestBase req) throws RestException, IOException {
req.addHeader("Accept", "application/json");
if (creds != null)
creds.authenticate(req);
HttpResponse resp = httpClient.execute(req);
HttpEntity ent = resp.getEntity();
StringBuilder result = new StringBuilder();
if (ent != null) {
String encoding = null;
if (ent.getContentEncoding() != null) {
encoding = ent.getContentEncoding().getValue();
}
if (encoding == null) {
Header contentTypeHeader = resp.getFirstHeader("Content-Type");
HeaderElement[] contentTypeElements = contentTypeHeader.getElements();
for (HeaderElement he : contentTypeElements) {
NameValuePair nvp = he.getParameterByName("charset");
if (nvp != null) {
encoding = nvp.getValue();
}
}
}
InputStreamReader isr = encoding != null ?
new InputStreamReader(ent.getContent(), encoding) :
new InputStreamReader(ent.getContent());
BufferedReader br = new BufferedReader(isr);
String line = "";
while ((line = br.readLine()) != null)
result.append(line);
}
StatusLine sl = resp.getStatusLine();
if (sl.getStatusCode() >= 300)
throw new RestException(sl.getReasonPhrase(), sl.getStatusCode(), result.toString());
return result.length() > 0 ? JSONSerializer.toJSON(result.toString()): null;
}
产生的错误是典型的链接异常,这通常意味着 SSL
证书不正确。由于证书是在 App Server 级别导入的,因此我希望 SSL
连接对 HttpsURLConnection
和 HttpClient
调用的处理方式相同。
Caused by: `com.ibm.jsse2.util.j: PKIX` path building failed: `java.security.cert.CertPathBuilderException: PKIXCertPathBuilderImpl` co
无法构建有效的 CertPath.;
内部原因是:
java.security.cert.CertPathValidatorException:
CN=Entrust Root Certification Authority颁发的证书,OU="(c) 2
006 Entrust, Inc.",OU=www.entrust.net/CPS 以引用方式并入,O="Entrust, Inc.",C=US 不受信任;内部原因是:
`java.security.cert.CertPathValidatorException:` Certificate chaining error
at com.ibm.jsse2.util.h.b(h.java:18) ~[na:6.0 build_20141024]
at com.ibm.jsse2.util.h.b(h.java:118) ~[na:6.0 build_20141024]
at com.ibm.jsse2.util.g.a(g.java:14) ~[na:6.0 build_20141024]
at com.ibm.jsse2.pc.a(pc.java:41) ~[na:6.0 build_20141024]
at com.ibm.jsse2.pc.checkServerTrusted(pc.java:1) ~[na:6.0 build_20141024]
at com.ibm.jsse2.pc.b(pc.java:90) ~[na:6.0 build_20141024]
at com.ibm.jsse2.lb.a(lb.java:499) ~[na:6.0 build_20141024]
... 80 common frames omitted
原因:java.security.cert.CertPathBuilderException:
PKIXCertPathBuilderImpl 无法构建有效的 CertPath。
在 com.ibm.security.cert.PKIXCertPathBuilderImpl.engineBuild(PKIXCertPathBuilderImpl.java:411)
~[na:na]
在 java.security.cert.CertPathBuilder.build(CertPathBuilder.java:258)
~[na:na]
在 com.ibm.jsse2.util.h.b(h.java:61) ~[na:6.0 build_20141024]
... 86
省略了公共帧
为什么要为 HttpsURLConnection
申请证书而不为 HttpClient
申请证书?我究竟做错了什么?
以下问题有一个很好的代码示例,说明如何通过 HttpClient 使用 HTTPS。
简而言之:您的代码缺少所有 HTTPS 特定设置。您正在使用它,就好像它只是一个普通的 HTTP 请求一样。
除非明确配置,否则 HttpClient 不会考虑系统属性。
尝试更换
HttpClients.createDefault()
和
HttpClients.createSystem()
另请注意,您的代码中未使用 PoolingHttpClientConnectionManager
实例。除非有充分的理由,否则不要创建自定义连接管理器。
我有一个网络应用程序(在 WebSphere 上)与第 3 方交互以格式化一些接收到的数据,然后 RESTful 调用驻留在 Tomcat server
上的第 3 方。在 Web 应用程序中,我可以使用 Java 的原生 HttpsUrlConnection
(见下文)成功进行基本的 RESTful GET
调用,但是当我使用 Apache 的 HttpClient
,它因 SSL
链接错误而失败。
HttpsURLConnection:
String urlWithParams = "https://example.com/rest/issue/59";
String methodType = "GET";
String acceptType = MediaType.APPLICATION_JSON;
HttpsURLConnection conn = null;
try {
URL url = new URL(urlWithParams);
conn = (HttpsURLConnection) url.openConnection();
conn.setRequestMethod(methodType);
conn.setRequestProperty("Accept", acceptType);
if (conn.getResponseCode() != 200) {
System.out.println("Failed. httpErrorUrl=" + conn.getResponseCode()
+ " httpErrorCode=" + conn.getResponseCode()
+ " httpErrorMsg=" + conn.getResponseMessage());
}
BufferedReader br = new BufferedReader(new InputStreamReader((conn.getInputStream())));
String rawData;
String toReturn = "";
while ((rawData = br.readLine()) != null) {
toReturn += rawData;
}
System.out.println(toReturn);
} catch (MalformedURLException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally{
if(conn != null){
conn.disconnect();
} else {
System.out.println("httpUrlConnection is null");
}
}
HttpClient代码:
String uri = "https://example.com/rest/issue/59";
PoolingHttpClientConnectionManager connManager = new PoolingHttpClientConnectionManager();
connManager.setDefaultMaxPerRoute(20);
connManager.setMaxTotal(40);
CloseableHttpClient httpclient = HttpClients.createDefault();
HttpClient 方法在以下函数中执行:
private JSON request(HttpRequestBase req) throws RestException, IOException {
req.addHeader("Accept", "application/json");
if (creds != null)
creds.authenticate(req);
HttpResponse resp = httpClient.execute(req);
HttpEntity ent = resp.getEntity();
StringBuilder result = new StringBuilder();
if (ent != null) {
String encoding = null;
if (ent.getContentEncoding() != null) {
encoding = ent.getContentEncoding().getValue();
}
if (encoding == null) {
Header contentTypeHeader = resp.getFirstHeader("Content-Type");
HeaderElement[] contentTypeElements = contentTypeHeader.getElements();
for (HeaderElement he : contentTypeElements) {
NameValuePair nvp = he.getParameterByName("charset");
if (nvp != null) {
encoding = nvp.getValue();
}
}
}
InputStreamReader isr = encoding != null ?
new InputStreamReader(ent.getContent(), encoding) :
new InputStreamReader(ent.getContent());
BufferedReader br = new BufferedReader(isr);
String line = "";
while ((line = br.readLine()) != null)
result.append(line);
}
StatusLine sl = resp.getStatusLine();
if (sl.getStatusCode() >= 300)
throw new RestException(sl.getReasonPhrase(), sl.getStatusCode(), result.toString());
return result.length() > 0 ? JSONSerializer.toJSON(result.toString()): null;
}
产生的错误是典型的链接异常,这通常意味着 SSL
证书不正确。由于证书是在 App Server 级别导入的,因此我希望 SSL
连接对 HttpsURLConnection
和 HttpClient
调用的处理方式相同。
Caused by: `com.ibm.jsse2.util.j: PKIX` path building failed: `java.security.cert.CertPathBuilderException: PKIXCertPathBuilderImpl` co
无法构建有效的 CertPath.;
内部原因是:
java.security.cert.CertPathValidatorException:
CN=Entrust Root Certification Authority颁发的证书,OU="(c) 2
006 Entrust, Inc.",OU=www.entrust.net/CPS 以引用方式并入,O="Entrust, Inc.",C=US 不受信任;内部原因是:
`java.security.cert.CertPathValidatorException:` Certificate chaining error
at com.ibm.jsse2.util.h.b(h.java:18) ~[na:6.0 build_20141024]
at com.ibm.jsse2.util.h.b(h.java:118) ~[na:6.0 build_20141024]
at com.ibm.jsse2.util.g.a(g.java:14) ~[na:6.0 build_20141024]
at com.ibm.jsse2.pc.a(pc.java:41) ~[na:6.0 build_20141024]
at com.ibm.jsse2.pc.checkServerTrusted(pc.java:1) ~[na:6.0 build_20141024]
at com.ibm.jsse2.pc.b(pc.java:90) ~[na:6.0 build_20141024]
at com.ibm.jsse2.lb.a(lb.java:499) ~[na:6.0 build_20141024]
... 80 common frames omitted
原因:java.security.cert.CertPathBuilderException:
PKIXCertPathBuilderImpl 无法构建有效的 CertPath。
在 com.ibm.security.cert.PKIXCertPathBuilderImpl.engineBuild(PKIXCertPathBuilderImpl.java:411)
~[na:na]
在 java.security.cert.CertPathBuilder.build(CertPathBuilder.java:258)
~[na:na]
在 com.ibm.jsse2.util.h.b(h.java:61) ~[na:6.0 build_20141024]
... 86
省略了公共帧
为什么要为 HttpsURLConnection
申请证书而不为 HttpClient
申请证书?我究竟做错了什么?
以下问题有一个很好的代码示例,说明如何通过 HttpClient 使用 HTTPS。
简而言之:您的代码缺少所有 HTTPS 特定设置。您正在使用它,就好像它只是一个普通的 HTTP 请求一样。
除非明确配置,否则 HttpClient 不会考虑系统属性。
尝试更换
HttpClients.createDefault()
和
HttpClients.createSystem()
另请注意,您的代码中未使用 PoolingHttpClientConnectionManager
实例。除非有充分的理由,否则不要创建自定义连接管理器。