httpclient發送https協議請求以及javax.net.ssl.SSLHandshakeException解決辦法

本人在作接口自動化的過程當中,遇到了請求第三方https協議請求,在通過了短暫的知識從新學習以後,寫完代碼執行起來老是遇到一個異常,在用客戶端執行請求的時候拋出來的,下面是異常的信息:html

Exception in thread "main" javax.net.ssl.SSLHandshakeException: Received fatal alert: handshake_failure
	at sun.security.ssl.Alerts.getSSLException(Alerts.java:192)
	at sun.security.ssl.Alerts.getSSLException(Alerts.java:154)
	at sun.security.ssl.SSLSocketImpl.recvAlert(SSLSocketImpl.java:2023)
	at sun.security.ssl.SSLSocketImpl.readRecord(SSLSocketImpl.java:1125)
	at sun.security.ssl.SSLSocketImpl.performInitialHandshake(SSLSocketImpl.java:1375)
	at sun.security.ssl.SSLSocketImpl.startHandshake(SSLSocketImpl.java:1403)
	at sun.security.ssl.SSLSocketImpl.startHandshake(SSLSocketImpl.java:1387)
	at org.apache.http.conn.ssl.SSLConnectionSocketFactory.createLayeredSocket(SSLConnectionSocketFactory.java:394)
	at org.apache.http.conn.ssl.SSLConnectionSocketFactory.connectSocket(SSLConnectionSocketFactory.java:353)
	at org.apache.http.impl.conn.DefaultHttpClientConnectionOperator.connect(DefaultHttpClientConnectionOperator.java:134)
	at org.apache.http.impl.conn.PoolingHttpClientConnectionManager.connect(PoolingHttpClientConnectionManager.java:353)
	at org.apache.http.impl.execchain.MainClientExec.establishRoute(MainClientExec.java:380)
	at org.apache.http.impl.execchain.MainClientExec.execute(MainClientExec.java:236)
	at org.apache.http.impl.execchain.ProtocolExec.execute(ProtocolExec.java:184)
	at org.apache.http.impl.execchain.RetryExec.execute(RetryExec.java:88)
	at org.apache.http.impl.execchain.RedirectExec.execute(RedirectExec.java:110)
	at org.apache.http.impl.client.InternalHttpClient.doExecute(InternalHttpClient.java:184)
	at org.apache.http.impl.client.CloseableHttpClient.execute(CloseableHttpClient.java:82)
	at org.apache.http.impl.client.CloseableHttpClient.execute(CloseableHttpClient.java:107)

查閱了不少資料,大部分都說是由於java自己安全機制引發的,從新去官網下載jar包替換便可。如下是修改方法:java

由於jdk中jce的安全機制致使報的錯,要去oracle官網下載對應的jce包替換jdk中的jce包。 jce所在地址: %JAVA_HOME%\jre\lib\security裏的local_policy.jar,US_export_policy.jarpython

JDK7 JDK8apache

具體異常教程以下:傳送門編程

在緣由的第二種裏面,有一個須要校驗自己的TLS的版本和服務端版本是否一致,我就是在這裏出了問題,致使的這個異常。由於我一直用的默認參數去建立新的套接字對象。下面是我用Charles攔截的請求的header信息:安全

上面圈起來的地方就是現實的服務器的TLS版本,相應地改掉本身代碼的中設置版本的地方便可。服務器

下面是個人代碼:大多數參考了網上的教程,本身作了一些修改,大同小異。下面是獲取SSLcontext對象的方法,實現了X509TrustManager接口,裏面方法不用修改。oracle

/**
	 * 獲取SSL套接字對象 重點重點:設置tls協議的版本
	 * 
	 * @return
	 */
	public static SSLContext createIgnoreVerifySSL() {
		SSLContext sslContext = null;// 建立套接字對象
		try {
			sslContext = SSLContext.getInstance("TLSv1.2");//指定TLS版本
		} catch (NoSuchAlgorithmException e) {
			SourceCode.getInstance().output("建立套接字失敗!", e);
		}
		// 實現X509TrustManager接口,用於繞過驗證
		X509TrustManager trustManager = new X509TrustManager() {
			@Override
			public void checkClientTrusted(java.security.cert.X509Certificate[] paramArrayOfX509Certificate,
					String paramString) throws CertificateException {
			}
 
			@Override
			public void checkServerTrusted(java.security.cert.X509Certificate[] paramArrayOfX509Certificate,
					String paramString) throws CertificateException {
			}
 
			@Override
			public java.security.cert.X509Certificate[] getAcceptedIssuers() {
				return null;
			}
		};
		try {
			sslContext.init(null, new TrustManager[] { trustManager }, null);//初始化sslContext對象
		} catch (KeyManagementException e) {
			SourceCode.getInstance().output("初始化套接字失敗!", e);
		}
		return sslContext;
	}

下面是建立https協議的client的方法,其中用到了鏈接池的使用:框架

/**
	 * 獲取https協議請求對象
	 * 
	 * @return
	 */
	public static CloseableHttpClient getCloseableHttpsClients() {
		// 採用繞過驗證的方式處理https請求
		SSLContext sslcontext = createIgnoreVerifySSL();
		// 設置協議http和https對應的處理socket連接工廠的對象
		Registry<ConnectionSocketFactory> socketFactoryRegistry = RegistryBuilder.<ConnectionSocketFactory> create()
				.register("http", PlainConnectionSocketFactory.INSTANCE)
				.register("https", new SSLConnectionSocketFactory(sslcontext)).build();
		PoolingHttpClientConnectionManager connManager = new PoolingHttpClientConnectionManager(socketFactoryRegistry);
		HttpClients.custom().setConnectionManager(connManager);
		// 建立自定義的httpsclient對象
		CloseableHttpClient client = HttpClients.custom().setConnectionManager(connManager).build();
		return client;
	}

還有一個繼承httpclient類,重寫createDefault()方法來實現請求https的,通過實驗,對於一些https協議是沒有問題的。socket

技術類文章精選

非技術文章精選

大咖風采

點擊查看公衆號地圖

相關文章
相關標籤/搜索