httpclient向HTTPS发送数据建立SSL连接时的错误

httpclient向HTTPS发送数据建立SSL连接时的异常

异常信息如下:

javax.net.ssl.SSLHandshakeException: sun.security.validator.ValidatorException: PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target

 

原因:服务器的证书不被信任。一般是这样造成的。

使用KEYTOOL工具创建证书,然后用TOMCAT启动后,在浏览器打开网站时,会出现证书不被信任的提示。当然,利用HTTPCLIENT向服务端HTTPS发送数据时,HTTPCLIENT也会检测服务端的证书是否被信任,不被信任就抛出上面的异常。

解决办法有两种,一种是使证书被客户端信任。另一种是使用HTTPCLIENT发送数据时不检测服务器证书是否可信。

 

第一种办法,使证书被信任。

 

找正规CA签发证书,或者自己签发证书(只能那一台客户机上可信)。找正规CA签发证书就不说了,自己签发证书呢,见我的其他文章。

 

我发现,自己签名的证书弄好之后,从客户端打开服务端地址时,不再提示上面的错误,但是还是不能发送数据。原因是什么呢?因为那台证书在客户端操作系统上可信,但是在JAVA的KEYSTORE里不可信,要把服务端的证书导入KEYSTORE库中

 

导入办法:

打开命令行窗口,并到<java-home>\lib\security\ 目录下,运行下面的命令:

keytool -import -noprompt -keystore cacerts -storepass changeit -alias yourEntry1 -file your.cer

 

your.cer是服务端导出的证书,其他可以默认。

 

第二种办法,使用HTTPCLIENT时不检测服务器证书是否可信

 

扩展HttpClient 类实现自动接受证书

 

因为这种方法自动接收所有证书,因此存在一定的安全问题,所以在使用这种方法前请仔细考虑您的系统的安全需求。具体的步骤如下:

 

•提供一个自定义的socket factory (test.MySecureProtocolSocketFactory )。这个自定义的类必须实现接口org.apache.commons.httpclient.protocol.SecureProtocolSocketFactory ,在实现接口的类中调用自定义的X509TrustManager(test.MyX509TrustManager) ,这两个类可以在随本文带的附件中得到

•创建一个org.apache.commons.httpclient.protocol.Protocol 的实例,指定协议名称和默认的端口号

Protocol myhttps = new Protocol("https", new MySecureProtocolSocketFactory (), 443);

 

•注册刚才创建的https 协议对象

Protocol.registerProtocol("https ", myhttps);

 

•然后按照普通编程 方式打开https 的目标地址,代码如下:

TestMain.java

package com.test.https;

import java.util.HashMap;
import java.util.Map;

import org.apache.http.HttpEntity;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.util.EntityUtils;

public class TestMain {

	private String url = "https://www.nuomi.com/?cid=002540";  
    private String charset = "gbk";  
    private HttpClientUtil httpClientUtil = null;  
      
    public TestMain(){  
      
    	httpClientUtil = new HttpClientUtil();  
    }  
      
    public void test(){  
     
    	String sourceUrl = url;  
     
        String httpOrgCreateTestRtn = httpClientUtil.doPost(sourceUrl,null,charset);  
        System.out.println("result:"+httpOrgCreateTestRtn);    	
    }  
      
    public static void main(String[] args){  
        TestMain main = new TestMain();  
        main.test();  
    }  
}

HttpClientUtil.jva

package com.test.https;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;

import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.NameValuePair;
import org.apache.http.client.HttpClient;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.util.EntityUtils;

public class HttpClientUtil {

	 public String doPost(String url,Map<String,String> map,String charset){  
	        HttpClient httpClient = null;  
	        HttpGet  httpGet = null;
	        String result = null;  
	        try{  
	          
	        	httpClient = new SSLClient();  
	            httpGet = new HttpGet(url);
	         
	            HttpResponse response = httpClient.execute(httpGet);  
	            if(response != null){
	            	
	                HttpEntity resEntity = response.getEntity();  
	                if(resEntity != null){  
	                    
	                	result = EntityUtils.toString(resEntity,charset);  
	                }  
	            }  
	            
	        }catch(Exception ex){  
	          
	        	ex.printStackTrace();  
	        }  
	        return result;  
	    }  
}
SSLClient.java
package com.test.https;

import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;

import javax.net.ssl.SSLContext;
import javax.net.ssl.TrustManager;
import javax.net.ssl.X509TrustManager;

import org.apache.http.conn.ClientConnectionManager;
import org.apache.http.conn.scheme.Scheme;
import org.apache.http.conn.scheme.SchemeRegistry;
import org.apache.http.conn.ssl.SSLSocketFactory;
import org.apache.http.impl.client.DefaultHttpClient;

public class SSLClient extends DefaultHttpClient{
	
	@SuppressWarnings("deprecation")
	public SSLClient() throws Exception{  
        super();  
        SSLContext ctx = SSLContext.getInstance("TLS");  
        X509TrustManager tm = new X509TrustManager() {  
                @Override  
                public void checkClientTrusted(X509Certificate[] chain,  
                        String authType) throws CertificateException {  
                }  
                @Override  
                public void checkServerTrusted(X509Certificate[] chain,  
                        String authType) throws CertificateException {  
                }  
                @Override  
                public X509Certificate[] getAcceptedIssuers() {  
                    return null;  
                }  
        };  
        ctx.init(null, new TrustManager[]{tm}, null);  
        SSLSocketFactory ssf = new SSLSocketFactory(ctx,SSLSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER);  
        ClientConnectionManager ccm = this.getConnectionManager();  
        SchemeRegistry sr = ccm.getSchemeRegistry();  
        sr.register(new Scheme("https", 443, ssf));  
    }  
}


  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
使用HttpClient发送HTTPS请求并配置连接池,可以按照以下步骤进行: 1. 创建SSLContext对象,用于HTTPS连接的安全认证。 ```java SSLContext sslContext = SSLContexts.createSystemDefault(); ``` 2. 创建ConnectionSocketFactory对象,用于连接池中的连接创建。 ```java SSLConnectionSocketFactory sslConnectionSocketFactory = new SSLConnectionSocketFactory(sslContext); ``` 3. 创建HttpClientConnectionManager对象,用于管理连接池中的连接。 ```java PoolingHttpClientConnectionManager poolingHttpClientConnectionManager = new PoolingHttpClientConnectionManager(Arrays.asList(sslConnectionSocketFactory)); poolingHttpClientConnectionManager.setMaxTotal(200);//设置最大连接数 poolingHttpClientConnectionManager.setDefaultMaxPerRoute(100);//设置每个路由最大连接数 ``` 4. 创建HttpClient对象,并设置连接池管理器。 ```java CloseableHttpClient httpClient = HttpClients.custom() .setConnectionManager(poolingHttpClientConnectionManager) .build(); ``` 5. 创建HttpPost对象,设置请求参数,并执行请求。 ```java HttpPost httpPost = new HttpPost("https://example.com/path"); httpPost.setEntity(new StringEntity("Hello, world!")); CloseableHttpResponse httpResponse = httpClient.execute(httpPost); ``` 完整的示例代码如下: ```java import org.apache.http.client.methods.CloseableHttpResponse; import org.apache.http.client.methods.HttpPost; import org.apache.http.entity.StringEntity; import org.apache.http.impl.client.CloseableHttpClient; import org.apache.http.impl.client.HttpClients; import org.apache.http.impl.conn.PoolingHttpClientConnectionManager; import org.apache.http.ssl.SSLContexts; import org.apache.http.conn.ssl.SSLConnectionSocketFactory; import javax.net.ssl.SSLContext; import java.util.Arrays; import java.io.IOException; public class HttpClientExample { public static void main(String[] args) throws IOException { SSLContext sslContext = SSLContexts.createSystemDefault(); SSLConnectionSocketFactory sslConnectionSocketFactory = new SSLConnectionSocketFactory(sslContext); PoolingHttpClientConnectionManager poolingHttpClientConnectionManager = new PoolingHttpClientConnectionManager(Arrays.asList(sslConnectionSocketFactory)); poolingHttpClientConnectionManager.setMaxTotal(200); poolingHttpClientConnectionManager.setDefaultMaxPerRoute(100); CloseableHttpClient httpClient = HttpClients.custom() .setConnectionManager(poolingHttpClientConnectionManager) .build(); HttpPost httpPost = new HttpPost("https://example.com/path"); httpPost.setEntity(new StringEntity("Hello, world!")); CloseableHttpResponse httpResponse = httpClient.execute(httpPost); System.out.println(httpResponse.getStatusLine().getStatusCode()); httpResponse.close(); httpClient.close(); } } ```

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值