基於HttpClient 4.3的可訪問自簽名HTTPS網站的新版工具類

來源:互聯網
上載者:User

標籤:httpclient   https   java   util   組件   

本文出處:http://blog.csdn.net/chaijunkun/article/details/40145685,轉載請註明。由於本人不定期會整理相關博文,會對相應內容作出完善。因此強烈建議在原始出處查看此文。


HttpClient在當今Java應用中的位置越來越重要。從該項目的變遷過程我們不難發現,其已經從apache-commons眾多的子項目中剝離,一躍成為如今的頂級項目,可見它的分量。然而隨著項目的升級和架構的調整,很多以前常用的類和方法都已被打上了@Deprecated註解,作為一個有代碼潔癖的程式猿,我們也有必要升級一下工具類,讓代碼更加整潔。

另外在項目中正好需要訪問https協議的介面,而對應的伺服器沒有購買商業CA頒發的正式受信認證,只是做了個自簽名(聯想一下12306網站購票時提示的那個警告資訊),預設情況下通過HttpClient訪問會拋出異常,在本文中也給出瞭解決辦法。


在HttpClient 4.x版本中引入了大量的構造器設計模式,很多的配置都不建議直接new出來,而且相關的API也有所改動,例如串連參數,以前是直接new出HttpConnectionParams對象後通過set方法逐一設定屬性,現在有了構造器,可以通過如下方式進行構造:

ConnectionConfig.custom().setCharset(Charsets.toCharset(defaultEncoding)).build();

SocketConfig.custom().setSoTimeout(100000).build();

基本情況就是這樣,接下來談下如何使用新的HttpClient來訪問自簽名https介面。

參閱CSDN博主noodies代碼,發現實現訪問自簽名https的要點就是建立一個自訂的SSLContext對象,該對象要有可以儲存信任密鑰的容器,還要有判斷當前串連是否受信任的策略,以及在SSL串連工廠中取消對所有主機名稱的驗證。他的代碼將會在本文最後貼出來,以下代碼均針對新HttpClient。


首先建立一個信任任何密鑰的策略。代碼很簡單,不去考慮憑證鏈結和授與類型,均認為是受信任的:

class AnyTrustStrategy implements TrustStrategy{@Overridepublic boolean isTrusted(X509Certificate[] chain, String authType) throws CertificateException {return true;}}

HttpClient既能處理常規http協議,又能支援https,根源在於在連線管理員中註冊了不同的串連建立工廠。當訪問url的schema為http時,調用明文串連套節工廠來建立串連;當訪問url的schema為https時,調用SSL串連通訊端工廠來建立串連。對於http的串連我們不做修改,只針對使用SSL的https串連來進行自訂:

RegistryBuilder<ConnectionSocketFactory> registryBuilder = RegistryBuilder.<ConnectionSocketFactory>create();ConnectionSocketFactory plainSF = new PlainConnectionSocketFactory();registryBuilder.register("http", plainSF);//指定信任金鑰儲存區對象和串連通訊端工廠try {KeyStore trustStore = KeyStore.getInstance(KeyStore.getDefaultType());SSLContext sslContext = SSLContexts.custom().useTLS().loadTrustMaterial(trustStore, new AnyTrustStrategy()).build();LayeredConnectionSocketFactory sslSF = new SSLConnectionSocketFactory(sslContext, SSLConnectionSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER);registryBuilder.register("https", sslSF);} catch (KeyStoreException e) {throw new RuntimeException(e);} catch (KeyManagementException e) {throw new RuntimeException(e);} catch (NoSuchAlgorithmException e) {throw new RuntimeException(e);}Registry<ConnectionSocketFactory> registry = registryBuilder.build();
在上述代碼中可以看到,首先建立了一個金鑰儲存區容器,隨後讓SSLContext開啟TLS,並將金鑰儲存區容器和信任任何主機的策略載入到該上下文中。構造SSL串連工廠時,將自訂的上下文和允許任何主機名稱通過校正的指令一併傳入。最後將這樣一個自訂的SSL串連工廠註冊到https協議上。

前期準備已經完成,接下來我們要獲得HttpClient對象:

//設定連線管理員PoolingHttpClientConnectionManager connManager = new PoolingHttpClientConnectionManager(registry);connManager.setDefaultConnectionConfig(connConfig);connManager.setDefaultSocketConfig(socketConfig);//構建用戶端HttpClient client= HttpClientBuilder.create().setConnectionManager(connManager).build();
為了讓我們的HttpClient具有多執行緒的能力,連線管理員選用了PoolingHttpClientConnectionManager,將協議註冊資訊傳入連線管理員,最後再次利用構造器的模式建立出我們需要的HttpClient。隨後的GET/POST請求發起方法http和https之間沒有差異。

為了驗證我們的代碼是否成功,可以做下JUnit單元測試:

@Testpublic void doTest() throws ClientProtocolException, URISyntaxException, IOException{HttpUtil util = HttpUtil.getInstance();InputStream in = util.doGet("https://kyfw.12306.cn/otn/leftTicket/init");String retVal = HttpUtil.readStream(in, HttpUtil.defaultEncoding);System.out.println(retVal);}

執行後可以在控制台看到12306餘票查詢介面的html代碼

為了方便大家使用,本人將封裝好的代碼上傳到了CSDN資源共用中,歡迎下載。

:http://download.csdn.net/detail/chaijunkun/8046331

最後感謝CSDN博主noodies的代碼提供了思路:http://blog.csdn.net/noodies/article/details/17240805

本文中的部分代碼參閱了HttpClient 4.3.5官方文檔的2.7節關於Connection socket factories的內容

基於HttpClient 4.3的可訪問自簽名HTTPS網站的新版工具類

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.