javax.net.ssl.SSLHandshakeException:異常原因及解決方案
報(bào)錯(cuò)原因
一般出現(xiàn)這種問(wèn)題是因?yàn)槟繕?biāo)服務(wù)器的證書(shū)問(wèn)題, 證書(shū)的 Subject Alternative Names 字段中沒(méi)有包含客戶端所使用的連接地址(這里是 IP 地址)
一般建議不要使用IP地址來(lái)進(jìn)行鏈接,如果實(shí)在是要用IP地址來(lái)進(jìn)行連接的話,有兩種處理方案:
方法一:可以將IP地址加入到服務(wù)器證書(shū)的 Subject Alternative Names 字段中;
方法二:在程序中進(jìn)行處理,繞過(guò)目標(biāo)服務(wù)器的安全驗(yàn)證
下面來(lái)介紹的就是方法二:在程序中繞過(guò)服務(wù)器的安全驗(yàn)證
在程序中繞過(guò)服務(wù)器的安全驗(yàn)證
以下就是繞過(guò)服務(wù)器驗(yàn)證的具體實(shí)現(xiàn)代碼
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.io.BufferedReader;
import java.io.DataOutputStream;
import java.io.InputStreamReader;
import java.net.URL;
import java.security.SecureRandom;
import javax.net.ssl.HttpsURLConnection;
import javax.net.ssl.HostnameVerifier;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSession;
import javax.net.ssl.SSLSocketFactory;
import javax.net.ssl.TrustManager;
import javax.net.ssl.X509TrustManager;
/**
* @author cbcbcb
*
*/
public class Test {
public static void main(String[] args) {
// 測(cè)試?yán)@過(guò)主機(jī)驗(yàn)證
String pathUrl ="https://IP:PORT/api/test";
String json = "{\"name\":\"ccc\"}";
StringBuffer sbf = new StringBuffer();
try {
// 創(chuàng)建信任所有證書(shū)的 TrustManager
TrustManager[] trustAllCerts = new TrustManager[]{
new X509TrustManager() {
@Override
public void checkClientTrusted(java.security.cert.X509Certificate[] chain, String authType) {
}
@Override
public void checkServerTrusted(java.security.cert.X509Certificate[] chain, String authType) {
}
@Override
public java.security.cert.X509Certificate[] getAcceptedIssuers() {
return new java.security.cert.X509Certificate[]{};
}
}
};
// 創(chuàng)建 SSLContext 并初始化
SSLContext sslContext = SSLContext.getInstance("SSL");
sslContext.init(null, trustAllCerts, new SecureRandom());
// 獲取 SSLSocketFactory
SSLSocketFactory ssf = sslContext.getSocketFactory();
// 創(chuàng)建繞過(guò)主機(jī)名驗(yàn)證的 HostnameVerifier
HostnameVerifier allHostsValid = new HostnameVerifier() {
@Override
public boolean verify(String hostname, SSLSession session) {
return true;
}
};
URL urlx = new URL(pathUrl);
HttpsURLConnection connection = (HttpsURLConnection) urlx.openConnection();
connection.setDoInput(true);
connection.setDoOutput(true);
connection.setRequestMethod("POST");
connection.setUseCaches(false);
connection.setInstanceFollowRedirects(true);
connection.addRequestProperty("Content-Type", "application/json");
connection.setRequestProperty("User-Agent", "Mozilla/4.0 (compatible; MSIE 5.0; Windows NT; DigExt)");
// 設(shè)置 SSLSocketFactory 和 HostnameVerifier
connection.setSSLSocketFactory(ssf);
connection.setHostnameVerifier(allHostsValid);
connection.connect();
DataOutputStream out = new DataOutputStream(connection.getOutputStream());
if (!"".equals(json)) {
out.write(json.getBytes());
}
out.flush();
out.close();
BufferedReader reader = new BufferedReader(new InputStreamReader(connection.getInputStream()));
String lines;
while ((lines = reader.readLine()) != null) {
lines = new String(lines.getBytes(), "UTF-8");
sbf.append(lines);
}
// System.out.println("crm返回參數(shù):" + sbf);
reader.close();
// 斷開(kāi)連接
connection.disconnect();
} catch (Exception e) {
e.printStackTrace();
}
System.out.println(decodeUnicode(sbf.toString()));
}
//下面這個(gè)方法是對(duì)輸出的內(nèi)容進(jìn)行編譯,有些接口返回的數(shù)據(jù)在輸出臺(tái)可能會(huì)是亂碼展示
//這個(gè)時(shí)候在什么方法都無(wú)用的情況下,可以通過(guò)這個(gè)方法將亂碼重新編譯成正確的展示
public static String decodeUnicode(String str) {
Pattern pattern = Pattern.compile("(\\\\u(\\p{XDigit}{4}))");
Matcher matcher = pattern.matcher(str);
char ch;
while (matcher.find()) {
ch = (char) Integer.parseInt(matcher.group(2), 16);
str = str.replace(matcher.group(1), ch + "");
}
return str;
}
}
注意點(diǎn)
在上面這串代碼中,有一些需要注意的一點(diǎn)就是在設(shè)置繞過(guò)驗(yàn)證的時(shí)候一定要注意設(shè)置的是對(duì)當(dāng)前實(shí)例繞過(guò)還是全部都繞過(guò),稍微有點(diǎn)不注意,設(shè)置成了全局的話,那么整個(gè)項(xiàng)目所有的鏈接都會(huì)收到相應(yīng)的影響,所以這里一定要注意注意再注意
HttpsURLConnection.setDefaultHostnameVerifier-----全局設(shè)置
//全局設(shè)置
HostnameVerifier allHostsValid = new HostnameVerifier() {
@Override
public boolean verify(String hostname, SSLSession session) {
return true;
}
};
HttpsURLConnection.setDefaultHostnameVerifier(allHostsValid);
connection.setHostnameVerifier(allHostsValid);-------設(shè)置對(duì)當(dāng)前實(shí)例的
// 創(chuàng)建繞過(guò)主機(jī)名驗(yàn)證的 HostnameVerifier
HostnameVerifier allHostsValid = new HostnameVerifier() {
@Override
public boolean verify(String hostname, SSLSession session) {
return true;
}
};
connection.setHostnameVerifier(allHostsValid);最后多說(shuō)一句
如果不好把控這個(gè)代碼究竟有沒(méi)有用的話,可以先不要更新到正式環(huán)境,先在本地或者測(cè)試服務(wù)器嘗試一下在更新
到此這篇關(guān)于javax.net.ssl.SSLHandshakeException:異常原因及解決方案的文章就介紹到這了,更多相關(guān)javax.net.ssl.SSLHandshakeException:異常內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Java中將MultipartFile和File互轉(zhuǎn)的方法詳解
我們?cè)陂_(kāi)發(fā)過(guò)程中經(jīng)常需要接收前端傳來(lái)的文件,通常需要處理MultipartFile格式的文件,今天來(lái)介紹一下MultipartFile和File怎么進(jìn)行優(yōu)雅的互轉(zhuǎn),需要的朋友可以參考下2023-10-10
SpringBoot返回long,前端接收進(jìn)度丟失,@JsonSerialize不生效問(wèn)題
這篇文章主要介紹了SpringBoot返回long,前端接收進(jìn)度丟失,@JsonSerialize不生效問(wèn)題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2024-08-08

