【发布时间】:2016-08-11 19:31:35
【问题描述】:
我有一个 Web 应用程序(在 WebSphere 上),它与第 3 方交互以格式化一些接收到的数据,然后对位于 Tomcat server 上的所述第 3 方进行 RESTful 调用。在 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 证书不正确。由于证书是在应用服务器级别导入的,我希望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 却没有?我究竟做错了什么?
【问题讨论】:
-
我猜这是 SNI 的问题,请参阅 stackoverflow.com/questions/5879894/android-ssl-sni-support。如果这篇文章是 2011 年的,它仍然是相关的。
标签: java ssl apache-httpclient-4.x httpsurlconnection