2012-09-11 56 views
8

任何人都可以帮助我开始使用Java中的服务器名称指示执行HTTP连接吗?Java上的服务器名称指示(SNI)

我试图从我管理的网站请求内容。我一直在使用Apache的HttpClient库,但是我对安全内容的请求失败,因为该网站只使用SNI作为HTTPS,并且在DefaultHttpClient中未启用SNI。我一直在寻找关于如何在Apache的HttpClient库中处理这个问题的指导,但我最终看到这个文档:http://hc.apache.org/httpclient-3.x/sslguide.html,它已经过期(当HttpClient和HttpCore是Apache公共包的一部分时,指的是代码)。

那么......有什么帮助吗?

回答

11

您可能需要跟踪https://issues.apache.org/jira/browse/HTTPCLIENT-1119

的Java 7的基本客户端实现能够支持它,并公开通过SSLSocketImpl#setHost功能(通过sun.net.www.protocol.https.HttpsClient

称为

上的Java 7使用

new URL("https://cmbntr.sni.velox.ch/").openStream() 

直到HttpClient的-1119是固定

+1

现在已经修复,可在HttpComponents HttpClient 4.3.2中找到。 –

+0

在OpenJDK的Tomcat中使用HttpClient 4.3.2(最高版本为“1.7.0_111”),SNI仍会失败。切换到Oracle HotSpot('1.7.0_80')后,SNI工作。对于在AWS Beanstalk上面临此问题的任何人,请查看此ebextension以将JVM切换到Oracle:https://gist.github.com/bremeld/6706980 – Sitati

0

看来这个问题已在Java 7中修复。

+1

感谢。我明白这是事实。但是,RFC并没有提供任何关于如何实现这一点的暗示(除非是从头开始构建自己的客户端)。任何想法的现有工具或如何使用Apache HttpClient的? – JellicleCat

1

什么工作对我来说是在Apache的配置正确配置ServerName

/etc/apache2/sites-avaible/default

<VirtualHost *:443> 
    ServerName foo.domain.com 
    ... 
</VirtualHost> 

https://stackoverflow.com/a/8058839/2088282说。

4

这是我如何org.apache.httpcomponents的HttpClient的V4.3 +

private HttpClientConnectionManager createConnectionManager(final SSLContext ctx) { 
    LOG.info("Creating sslConnectionSocketFactory"); 
    final SSLConnectionSocketFactory sslSF = new SSLConnectionSocketFactory(ctx) { 

     @Override 
     protected void prepareSocket(SSLSocket socket) throws IOException { 
      try { 
       System.out.println("************ setting socket HOST property *************"); 
       PropertyUtils.setProperty(socket, HOST, Constants.SNI_HOST); 
      } catch (IllegalAccessException | NoSuchMethodException | InvocationTargetException ex) { 
       LOG.error(ex.getMessage()); 
      } 
      super.prepareSocket(socket); 
     } 

    }; 

    LOG.info("Creating connectionRegistry"); 
    final Registry<ConnectionSocketFactory> registry = RegistryBuilder.<ConnectionSocketFactory>create() 
      .register("https", sslSF) 
      .build(); 

    LOG.info("Creating poolingConnectionManager"); 
    final PoolingHttpClientConnectionManager connectionManager = new PoolingHttpClientConnectionManager(registry); 
    connectionManager.setDefaultMaxPerRoute(MAX_CONNECTIONS_PER_ROUTE); 
    connectionManager.setMaxTotal(MAX_CONNECTIONS); 

    return connectionManager; 
} 

做到了,这是我创建的HttpClient

final KeyManager[] keyManagers = createKeyManagers(); 
final TrustManager[] trustManagers = createTrustManagers(); 
final SSLContext ctx = createSslContext(keyManagers, trustManagers); 

final HttpClientConnectionManager connectionManager = createConnectionManager(ctx); 

LOG.info("Creating httpClient"); 
HttpClient httpClient = HttpClients 
     .custom() 
     .setConnectionManager(connectionManager) 
     .build(); 
+0

请不要使用SSLConnectionSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER。 – Bruno

+0

一些澄清这些,因为我是谁可能会好奇: 'PropertyUtils'是'公地beanutils' '字符串HOST =“宿主”;' 'Constants.SNI_HOST'是服务器的DNS主机名你想连接到。 最重要的是:**使用httpclient 4.5.2不再需要定制工厂** –

+0

@DaanReid - “不再需要定制工厂”的含义是什么?有没有我们可以使用的默认实现。 – Shyam

相关问题