【问题标题】:How can I do an HttpPost using HttpClient to an HTTPS endpoint?如何使用 HttpClient 对 HTTPS 端点执行 HttpPost?
【发布时间】:2012-05-14 19:51:01
【问题描述】:

每当我尝试发布到 https 端点时,我都会收到 javax.net.ssl.SSLException: java.lang.NullPointerException :

import org.apache.commons.httpclient.MultiThreadedHttpConnectionManager;
import org.apache.commons.httpclient.methods.GetMethod;
import org.apache.commons.httpclient.HttpClient;

try {
    MultiThreadedHttpConnectionManager connectionManager = new MultiThreadedHttpConnectionManager();
    HttpClient httpClient = new HttpClient(connectionManager);
    PostMethod pm = new PostMethod("https://www.random.org");
    httpClient.executeMethod(pm);
} catch (Exception e) {
    e.printStackTrace();
}

这给了我:

javax.net.ssl.SSLException: java.lang.NullPointerException
    at com.sun.net.ssl.internal.ssl.Alerts.getSSLException(Alerts.java:190)
    at com.sun.net.ssl.internal.ssl.SSLSocketImpl.fatal(SSLSocketImpl.java:1731)
    at com.sun.net.ssl.internal.ssl.SSLSocketImpl.fatal(SSLSocketImpl.java:1692)
    at com.sun.net.ssl.internal.ssl.SSLSocketImpl.handleException(SSLSocketImpl.java:1675)
    at com.sun.net.ssl.internal.ssl.SSLSocketImpl.handleException(SSLSocketImpl.java:1601)
    at com.sun.net.ssl.internal.ssl.AppOutputStream.write(AppOutputStream.java:94)
    at java.io.BufferedOutputStream.flushBuffer(BufferedOutputStream.java:65)
    at java.io.BufferedOutputStream.flush(BufferedOutputStream.java:123)
    at org.apache.commons.httpclient.HttpConnection.flushRequestOutputStream(HttpConnection.java:828)
    at org.apache.commons.httpclient.MultiThreadedHttpConnectionManager$HttpConnectionAdapter.flushRequestOutputStream(MultiThreadedHttpConnectionManager.java:1565)
    at org.apache.commons.httpclient.HttpMethodBase.writeRequest(HttpMethodBase.java:2116)
    at org.apache.commons.httpclient.HttpMethodBase.execute(HttpMethodBase.java:1096)
    at org.apache.commons.httpclient.HttpMethodDirector.executeWithRetry(HttpMethodDirector.java:398)
    at org.apache.commons.httpclient.HttpMethodDirector.executeMethod(HttpMethodDirector.java:171)
    at org.apache.commons.httpclient.HttpClient.executeMethod(HttpClient.java:397)
    at org.apache.commons.httpclient.HttpClient.executeMethod(HttpClient.java:323)
    at <My File>
Caused by: java.lang.NullPointerException
    at org.bouncycastle.jce.provider.JCEECPublicKey.<init>(Unknown Source)
    at org.bouncycastle.jce.provider.JDKKeyFactory.createPublicKeyFromPublicKeyInfo(Unknown Source)
    at org.bouncycastle.jce.provider.X509CertificateObject.getPublicKey(Unknown Source)
    at sun.security.validator.PKIXValidator.initCommon(PKIXValidator.java:92)
    at sun.security.validator.PKIXValidator.<init>(PKIXValidator.java:60)
    at sun.security.validator.Validator.getInstance(Validator.java:161)
    at com.sun.net.ssl.internal.ssl.X509TrustManagerImpl.getValidator(X509TrustManagerImpl.java:108)
    at com.sun.net.ssl.internal.ssl.X509TrustManagerImpl.checkServerTrusted(X509TrustManagerImpl.java:204)
    at com.sun.net.ssl.internal.ssl.X509TrustManagerImpl.checkServerTrusted(X509TrustManagerImpl.java:249)
    at com.sun.net.ssl.internal.ssl.ClientHandshaker.serverCertificate(ClientHandshaker.java:1185)
    at com.sun.net.ssl.internal.ssl.ClientHandshaker.processMessage(ClientHandshaker.java:136)
    at com.sun.net.ssl.internal.ssl.Handshaker.processLoop(Handshaker.java:593)
    at com.sun.net.ssl.internal.ssl.Handshaker.process_record(Handshaker.java:529)
    at com.sun.net.ssl.internal.ssl.SSLSocketImpl.readRecord(SSLSocketImpl.java:925)
    at com.sun.net.ssl.internal.ssl.SSLSocketImpl.performInitialHandshake(SSLSocketImpl.java:1170)
    at com.sun.net.ssl.internal.ssl.SSLSocketImpl.writeRecord(SSLSocketImpl.java:637)
    at com.sun.net.ssl.internal.ssl.AppOutputStream.write(AppOutputStream.java:89)

我没有在我的机器上专门配置 SSL,但我运行的 JSSE 测试脚本似乎表明它已安装。我是否跳过了一个必要的步骤? NullPointerException 让我认为这可能是一个错误,而不是预期的错误。

2012 年 5 月 15 日编辑:

我已经使用 eclipse 调试器进行了深入研究,直到可以在 SSLSocketFactoryImpl 中看到证书。

SchemeSocketFactory socketfac = httpClient.getConnectionManager().getSchemeRegistry().getScheme("https").getSchemeSocketFactory();
socketfac.socketfactory.context.trustManager.trustedCerts.map.table, in debugger.

我可以找到我要访问的网站的证书;问题是,在此过程中,表中有一个空指针异常。 (见附图。)如果我使用调试器删除条目集中产生 NPE 的 2 个(共 183 个)条目,我的代码运行得非常好,但这似乎不是一个可行的解决方案。我认为这不是我的密钥库本身的问题 - 如果我使用 keytool -list -keystore cacerts,它会输出 183 个条目,并且每个条目的格式似乎都正确。




【问题讨论】:

  • 小心,您使用的是过时的 commons-httpclient 库。您现在应该使用新的 HttpComponents 库 hc.apache.org
  • 您使用 BouncyCastle 提供程序的任何原因?
  • @Bruno:我正在将代码作为更大的 Tomcat 服务的一部分运行,并且……这就是它的默认设置?我如何使用不同的提供商?
  • 我很惊讶在您的异常中看到那些 bouncycastle 痕迹。我希望它来自您的应用程序的某些部分,通过Security.insertProviderAt(..., 0) 或在列表in the JRE configuration 中的更高位置将 BC 作为安全提供程序添加到列表顶部。我也很惊讶它试图实例化一个JCEECPublicKey (EC),其中公钥是 RSA。您使用的是哪个版本的 BC 库?
  • @Bruno:从调试器中添加了更多信息。我似乎将 BC 作为 Maven 依赖项的一部分引入,该依赖项正在其他地方使用。 mvnrepository.com/artifact/bouncycastle/bcprov-jdk15/133

标签: java debugging ssl httpclient


【解决方案1】:

终于找到答案了。我将使用 Maven 的 bouncycastle 版本 133 作为项目的单独部分所需的另一个工件的一部分。我的解决方案是在我的 maven pom.xml 文件中将 bouncycastle 的 versionId 升级为 140。

【讨论】:

  • 我没有意识到你已经解决了你的问题。版本 140 是 still quite old,我会考虑更新的版本。
  • 你是对的。根据您在下面的回答,我对 com.bouncycastle 1.46 进行了进一步升级。
【解决方案2】:

版本133 is about 6 years old。已经有a number of fixes since。最新版本是 1.47,可在 org.bouncycaste group ID (no longer bouncycastle) 下获得。如果您查看发行说明,则会发现许多导致 NullPointerExceptions 的错误修复。

我还怀疑某些代码在不需要时使用 BouncyCastle 提供程序而不是 Sun 提供程序,无论是明确地还是因为使用 Security.insertProviderAt(...) 将 BC 提供程序插入到默认 Sun/Oracle 提供程序之前。

【讨论】:

    【解决方案3】:

    代码对我有用。启用调试日志以查看发生了什么。

      java.util.logging.Logger.getLogger("org.apache.http.wire").setLevel(java.util.logging.Level.FINEST);
      java.util.logging.Logger.getLogger("org.apache.http.headers").setLevel(java.util.logging.Level.FINEST);
    
      System.setProperty("org.apache.commons.logging.Log", "org.apache.commons.logging.impl.SimpleLog");
      System.setProperty("org.apache.commons.logging.simplelog.showdatetime", "true");
      System.setProperty("org.apache.commons.logging.simplelog.log.httpclient.wire", "debug");
      System.setProperty("org.apache.commons.logging.simplelog.log.org.apache.http", "debug");
      System.setProperty("org.apache.commons.logging.simplelog.log.org.apache.http.headers", "debug");
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2020-01-10
      • 2014-04-10
      • 1970-01-01
      • 2013-05-29
      • 1970-01-01
      • 1970-01-01
      • 2021-05-15
      相关资源
      最近更新 更多