標籤: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網站的新版工具類