在使用 HttpClient 工具調用第三方 Http 接口時報錯 javax.net.ssl.SSLException:Unrecognized SSL message,plaintext connection?
這個錯誤意思是說,無法識別 SSL 信息,明文連接?
看這個意思是說在使用 https 協議訪問網絡資源時無法識別 SSL 信息。
SSL(Secure Socket Layer 安全套接層)是基於HTTPS下的一個協議加密層,最初是由網景公司(Netscape)研發,后被IETF(The Internet Engineering Task Force - 互聯網工程任務組)標准化后寫入(RFCRequest For Comments 請求注釋),RFC里包含了很多互聯網技術的規范!
起初是因為HTTP在傳輸數據時使用的是明文(雖然說POST提交的數據時放在報體里看不到的,但是還是可以通過抓包工具竊取到)是不安全的,為了解決這一隱患網景公司推出了SSL安全套接字協議層,SSL是基於HTTP之下TCP之上的一個協議層,是基於HTTP標准並對TCP傳輸數據時進行加密,所以HPPTS是HTTP+SSL/TCP的簡稱。
SSL協議位於TCP/IP協議與各種應用層協議之間,為數據通訊提供安全支持。SSL協議可分為兩層: SSL記錄協議(SSL Record Protocol):它建立在可靠的傳輸協議(如TCP)之上,為高層協議提供數據封裝、壓縮、加密等基本功能的支持。 SSL握手協議(SSL Handshake Protocol):它建立在SSL記錄協議之上,用於在實際的數據傳輸開始前,通訊雙方進行身份認證、協商加密算法、交換加密密鑰等。
本來 https 是在 http 的基礎上進行加密。使用 SSL 協議進行加密。
這樣通訊的雙方在通訊前就要去做身份校驗,通過證書的方式驗證身份。
原來是證書方面的問題,需要我們加一下代碼,使其信任所有證書。
如下代碼,設置信任所有代理。
import org.apache.http.conn.ssl.NoopHostnameVerifier; import org.apache.http.conn.ssl.SSLConnectionSocketFactory; import org.apache.http.impl.client.CloseableHttpClient; import org.apache.http.impl.client.HttpClients; import org.apache.http.ssl.SSLContextBuilder; import org.apache.http.ssl.TrustStrategy; import javax.net.ssl.HostnameVerifier; import javax.net.ssl.SSLContext; import java.security.KeyManagementException; import java.security.KeyStoreException; import java.security.NoSuchAlgorithmException; import java.security.cert.CertificateException; import java.security.cert.X509Certificate; public class HttpClientUtil{ public static CloseableHttpClient createSSLClientDefault() { try { //使用 loadTrustMaterial() 方法實現一個信任策略,信任所有證書 SSLContext sslContext = new SSLContextBuilder().loadTrustMaterial(null, new TrustStrategy() { // 信任所有 public boolean isTrusted(X509Certificate[] chain, String authType) throws CertificateException { return true; } }).build(); //NoopHostnameVerifier類: 作為主機名驗證工具,實質上關閉了主機名驗證,它接受任何 //有效的SSL會話並匹配到目標主機。 HostnameVerifier hostnameVerifier = NoopHostnameVerifier.INSTANCE; SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory(sslContext, hostnameVerifier); return HttpClients.custom().setSSLSocketFactory(sslsf).build(); } catch (KeyManagementException e) { e.printStackTrace(); } catch (NoSuchAlgorithmException e) { e.printStackTrace(); } catch (KeyStoreException e) { e.printStackTrace(); } return HttpClients.createDefault(); } }
獲取HttpClient 實例的方式由使用默認的 httpclient 變為我們自定義的 httpclient 實例
即,由
變為
這解決了我的問題。