詳解Java如何向http/https接口發(fā)出請(qǐng)求
用Java發(fā)送web請(qǐng)求所用到的包都在java.net
下,在具體使用時(shí)可以用如下代碼,你可以把它封裝成一個(gè)工具類
import javax.net.ssl.*; import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; import java.io.OutputStream; import java.net.HttpURLConnection; import java.net.URL; import java.security.SecureRandom; import java.security.cert.CertificateException; import java.security.cert.X509Certificate; public class Testt { /* HostnameVerifier 是一個(gè)Java接口 其中的verify方法用來在下面的類中提供主機(jī)名的SSL校驗(yàn) 這里個(gè)人用不做具體校驗(yàn)所有的主機(jī)名都給過 */ final static HostnameVerifier DO_NOT_VERIFY = new HostnameVerifier() { public boolean verify(String arg0, SSLSession arg1) { return true; } }; /* trustAllHosts方法 方法創(chuàng)建了一個(gè) TrustManager 接口的匿名實(shí)現(xiàn) 它是用來檢查證書的,無論是服務(wù)器證書還是客戶端證書 這通過重寫 checkServerTrusted 和 checkClientTrusted 方法為空 不做任何檢查 */ public static void trustAllHosts() { TrustManager[] trustAllCerts = new TrustManager[] {new X509TrustManager() { public X509Certificate[] getAcceptedIssuers() { return new X509Certificate[] {}; } public void checkServerTrusted(X509Certificate[] arg0, String arg1) throws CertificateException { } public void checkClientTrusted(X509Certificate[] arg0, String arg1) throws CertificateException { } } }; /* SSLContext 使用上述的 TrustManager 初始化一個(gè) SSLContext 實(shí)例 并將其設(shè)置為 HttpsURLConnection 的默認(rèn) SSLSocketFactory 這允許 HttpsURLConnection 信任所有SSL證書 TLS是握手協(xié)議的一種 */ try { SSLContext sc = SSLContext.getInstance("TLS"); sc.init(null, trustAllCerts, new SecureRandom()); HttpsURLConnection.setDefaultSSLSocketFactory(sc.getSocketFactory()); } catch (Exception e) { e.printStackTrace(); } } /** * 發(fā)出請(qǐng)求的具體方法 * @param urlPath https協(xié)議接口的路徑 https://xxxxxx * @param Json 發(fā)出請(qǐng)求需要攜帶的參數(shù),需要是Json格式 * @return */ public static String doPostToJson(String urlPath, String Json) { String result = ""; BufferedReader reader = null; HttpURLConnection conn = null; try { /* 掉用上面的靜態(tài)方法,使得請(qǐng)求發(fā)出時(shí),作為調(diào)用者的我們對(duì)服務(wù)端所擁有的任何https證書都是兼容的 這里說一句題外話:一般情況下,作為接口使用者trustAllHosts方法里面的代碼是不變的,因?yàn)槟阕鳛槭褂谜? 總沒道理說讓人家服務(wù)端兼容你什么,除非你是證書的使用者,不過這種情況會(huì)有證書廠商 告訴你如何做,不得不說廠商服務(wù)是個(gè)好東西 */ trustAllHosts(); URL url = new URL(urlPath); /* 如果協(xié)議是 https,則使用 HttpsURLConnection 并設(shè)置 HostnameVerifier 為 DO_NOT_VERIFY。 否則,使用 HttpURLConnection */ if (url.getProtocol().toLowerCase().equals("https")) { HttpsURLConnection httpsConn = (HttpsURLConnection) url.openConnection(); httpsConn.setHostnameVerifier(DO_NOT_VERIFY); conn = httpsConn; } else { conn = (HttpURLConnection) url.openConnection(); } // 設(shè)置請(qǐng)求以POST形式發(fā)出 conn.setRequestMethod("POST"); // 是否攜帶請(qǐng)求提,POST和GET請(qǐng)求必須為true conn.setDoOutput(true); // 是否會(huì)獲取服務(wù)端的響應(yīng),默認(rèn)是true conn.setDoInput(true); //禁用緩存 conn.setUseCaches(false); // Keep-Alive告訴服務(wù)端對(duì)已有的TCP連接保持一定時(shí)間的活性,以保障后續(xù)發(fā)出的請(qǐng)求不需要建立新的TCP連接,從而減少網(wǎng)絡(luò)開銷 conn.setRequestProperty("Connection", "Keep-Alive"); //字符集,這個(gè)配置不是標(biāo)準(zhǔn)的請(qǐng)求頭,但是有些妖孽系統(tǒng)會(huì)讀取這個(gè) conn.setRequestProperty("Charset", "UTF-8"); // 這個(gè)是請(qǐng)求格式,告訴服務(wù)端這個(gè)請(qǐng)求發(fā)送的是Json數(shù)據(jù)以及字符集 conn.setRequestProperty("Content-Type", "application/json; charset=UTF-8"); // 告訴服務(wù)端,相應(yīng)格式也希望是json格式 conn.setRequestProperty("accept", "application/json"); //如果參數(shù)不為空則將參數(shù)以字節(jié)數(shù)流的方式寫入請(qǐng)求體里面 if (Json != null) { byte[] writebytes = Json.getBytes(); conn.setRequestProperty("Content-Length", String.valueOf(writebytes.length)); OutputStream outwritestream = conn.getOutputStream(); outwritestream.write(Json.getBytes()); outwritestream.flush(); outwritestream.close(); } //讀取響應(yīng),相應(yīng)數(shù)據(jù)也是一個(gè)json if (conn.getResponseCode() == 200) { reader = new BufferedReader(new InputStreamReader(conn.getInputStream(), "utf-8")); result = reader.readLine(); } } catch (Exception e) { e.printStackTrace(); } finally { //讀取相應(yīng)用的輸入流需要在這里關(guān)閉,而寫入請(qǐng)求參數(shù)的輸出流是隨用隨關(guān)的 if (reader != null) { try { reader.close(); conn.disconnect(); } catch (IOException e) { e.printStackTrace(); } } } return result; } }
對(duì)于上面的代碼,重點(diǎn)要說明的第一點(diǎn)是HostnameVerifier
接口提供的方法,它主要用于訪問https協(xié)議下的接口時(shí),驗(yàn)證當(dāng)前已和你建立連接的hostname(主機(jī)名)和連接的SSLSession(SSL會(huì)話)證書是否匹配,防止中間人攻擊,比如可以如下操作
import javax.net.ssl.HostnameVerifier; import javax.net.ssl.HttpsURLConnection; import javax.net.ssl.SSLSession; import java.io.IOException; import java.net.URL; public class HostnameVerifierExample { public static void main(String[] args) { try { // 創(chuàng)建一個(gè)URL對(duì)象 URL url = new URL("https://xxxxx"); // 打開HTTPS連接 HttpsURLConnection connection = (HttpsURLConnection) url.openConnection(); // 設(shè)置自定義的HostnameVerifier HostnameVerifier customVerifier = new HostnameVerifier() { @Override public boolean verify(String hostname, SSLSession session) { // 在這里實(shí)現(xiàn)你的驗(yàn)證邏輯 // 例如,你可以比較hostname和session中的證書信息 // 為了簡(jiǎn)單起見,這里我們直接接受任何主機(jī)名(不推薦這樣做,有安全風(fēng)險(xiǎn)) // 在實(shí)際應(yīng)用中,你應(yīng)該根據(jù)你的安全策略來實(shí)現(xiàn)這個(gè)邏輯 // 比如,你可以檢查hostname是否與你預(yù)期的服務(wù)器主機(jī)名匹配 // 或者,你可以使用HttpsURLConnection.getDefaultHostnameVerifier()來獲取默認(rèn)的驗(yàn)證器,并基于它的結(jié)果進(jìn)行擴(kuò)展 // 這是一個(gè)不安全的示例,僅用于說明如何使用verify方法 // 在實(shí)際應(yīng)用中,你應(yīng)該避免這樣做 return true; // 更安全的做法可能是這樣的: // if ("expected.hostname".equals(hostname)) { // return true; // } else { // HostnameVerifier defaultVerifier = HttpsURLConnection.getDefaultHostnameVerifier(); // return defaultVerifier.verify(hostname, session); // } } }; // 設(shè)置自定義的HostnameVerifier到連接中 connection.setHostnameVerifier(customVerifier); // 繼續(xù)處理HTTPS連接,比如讀取響應(yīng)等 // ... // 關(guān)閉連接 connection.disconnect(); } catch (IOException e) { e.printStackTrace(); } } }
第二是trustAllHosts方法里面的東西,TrustManager是用來實(shí)現(xiàn)證書驗(yàn)證的類,X509TrustManager是X.509 證書的驗(yàn)證實(shí)現(xiàn),通俗的講是一個(gè)基礎(chǔ)的證書,因此我上面的代碼中也說了,如果你是正式的https證書使用者,會(huì)有廠商服務(wù)告訴你怎么驗(yàn)證證書,在X509TrustManager 中提供了三個(gè)方法
getAcceptedIssuers():返回此信任管理器接受的發(fā)行者證書(根證書或中間證書)數(shù)組。在上面的代碼中,這個(gè)方法返回了一個(gè)空數(shù)組,意味著它不做任何特定的發(fā)行者證書獲取
checkServerTrusted(X509Certificate[] certs, String authType):驗(yàn)證服務(wù)器提供的證書鏈?zhǔn)欠窨尚?。在代碼中,這個(gè)方法被空實(shí)現(xiàn)了,意味著不會(huì)進(jìn)行任何驗(yàn)證。
checkClientTrusted(X509Certificate[] certs, String authType):驗(yàn)證客戶端提供的證書鏈?zhǔn)欠窨尚牛ㄔ谛枰蛻舳俗C書的情況下)。同樣,在代碼中,這個(gè)方法也被空實(shí)現(xiàn)了
到此這篇關(guān)于詳解Java如何向http/https接口發(fā)出請(qǐng)求的文章就介紹到這了,更多相關(guān)Java https接口發(fā)出請(qǐng)求內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Spring5學(xué)習(xí)之基礎(chǔ)知識(shí)總結(jié)
這篇文章主要介紹了Spring5學(xué)習(xí)之基礎(chǔ)知識(shí)總結(jié),文中有非常詳細(xì)的代碼示例,對(duì)正在學(xué)習(xí)java的小伙伴們有非常好的幫助,需要的朋友可以參考下2021-05-05Java數(shù)據(jù)結(jié)構(gòu)之簡(jiǎn)單鏈表的定義與實(shí)現(xiàn)方法示例
這篇文章主要介紹了Java數(shù)據(jù)結(jié)構(gòu)之簡(jiǎn)單鏈表的定義與實(shí)現(xiàn)方法,簡(jiǎn)單描述了鏈接的概念、原理,并結(jié)合實(shí)例形式分析了java定義與使用鏈表的相關(guān)步驟與操作技巧,需要的朋友可以參考下2017-10-10SpringMVC @RequestMapping注解應(yīng)用方法示例講解
通過@RequestMapping注解可以定義不同的處理器映射規(guī)則,下面這篇文章主要給大家介紹了關(guān)于SpringMVC中@RequestMapping注解用法的相關(guān)資料,文中通過實(shí)例代碼介紹的非常詳細(xì),需要的朋友可以參考下2022-09-09淺談Java日志框架slf4j作用及其實(shí)現(xiàn)原理
日志記錄是應(yīng)用程序運(yùn)行中必不可少的一部分。這篇文章主要介紹了淺談Java日志框架slf4j作用及其實(shí)現(xiàn)原理,SLF4J是一個(gè)日志框架抽象層,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2018-03-03Spring Boot Mail QQ企業(yè)郵箱無法連接解決方案
這篇文章主要介紹了Spring Boot Mail QQ企業(yè)郵箱無法連接解決方案,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2020-09-09