2012-09-11 55 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

相關問題