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-10SpringBoot返回long,前端接收進(jìn)度丟失,@JsonSerialize不生效問(wèn)題
這篇文章主要介紹了SpringBoot返回long,前端接收進(jìn)度丟失,@JsonSerialize不生效問(wèn)題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2024-08-08