使用https URL,HttpsURLConnection可以正常工作,但HttpClient不能

时间:2016-04-19 14:32:41

标签: java ssl apache-httpclient-4.x httpsurlconnection

我有一个Web应用程序(在WebSphere上),它与第三方交互以格式化一些接收到的数据,然后对驻留在Tomcat server的第三方进行RESTful调用。在Web应用程序中,我可以使用Java的本地GET(见下文)成功进行基本的RESTful HttpsUrlConnection调用,但是当我使用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级别导入的,因此我希望SSLHttpsURLConnection调用的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?我究竟做错了什么?

2 个答案:

答案 0 :(得分:2)

除非明确配置为执行此操作,否则HttpClient不会考虑系统属性。

尝试替换

HttpClients.createDefault()

HttpClients.createSystem()

另请注意,代码中的PoolingHttpClientConnectionManager实例未使用。除非您有充分的理由这样做,否则不要创建自定义连接管理器。

答案 1 :(得分:0)

以下问题有关于如何在HttpClient上使用HTTPS的良好代码示例。

Using Apache httpclient for https

简而言之:您的代码缺少所有HTTP S 特定设置..您正在使用它,就像它只是一个常规的HTTP请求一样。