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

