HttpClient可以直接请求https,为何要绕过ssl证书验证?

本程序使用的HttpClient版本:   httpclient4.5.2    

一个有意思的现象,看下面这段获取百度首页代码的HttpClient请求:

import java.io.IOException;

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 TestApp {
	public static void main(String[] args) {
		 CloseableHttpClient client=HttpClients.createDefault();
	        String url="https://www.baidu.com/";
	        HttpGet httpGet=new HttpGet(url);
	        //处理响应部分
	        CloseableHttpResponse response =null;
	        try {
	            response = client.execute(httpGet);
	            HttpEntity entity = response.getEntity();
	            System.out.println("获取到的内容:"+EntityUtils.toString(entity,"UTF-8"));
	            EntityUtils.consume(entity);//关闭entity
	        } catch (Exception e) {
	            e.printStackTrace();
	        } finally{
	            if (client!=null) {
	                try {client.close();} catch (IOException e) {e.printStackTrace();}
	            }
	            if (response!=null) {
	                try {response.close();} catch (IOException e) {e.printStackTrace();}
	            }
	        }
	}
}

执行结果:

 

你有没有一个疑问,我通过httpclient明明可以访问https的网址,为什么网上还有铺天盖地的文章,说是“httpclient如何绕过ssl证书验证”、“httpclient完美实现信任所有的https请求”这样之类的文章呢?既然我什么都不需要做,只通过如上简单的几句代码就可以访问https,为什么还要写很多额外不知道有什么用处的代码去绕过所谓的ssl验证?为什么呢?存在自然有它的道理,上面的代码什么不需要改,把“https://www.baidu.com/”改为“https://www.12306.cn/mormhweb/”,再运行程序,很奇怪的发现结果如下:

 

这是为什么呢?这就是为什么会写那么多代码让httpclient绕过ssl验证的原因:

来看下12306的https路径:

 

这里提示的不安全的,而第一次请求的百度的网址却是安全的:

 

因此,确切的说我们之所以要让httpclient绕过ssl验证,就是为了避免访问浏览器提示不安全的https链接出现异常的情况,特别是我们开发系统接口调用的时候,经常是https的接口,而又是不安全的,此时使用httpclient就无法正确调用,因此要写绕过ssl验证的代码。

那么这段代码怎么写?每个httpclient的版本还不一样,我这里使用的是httpclient4.5.2,实现如下:

import java.io.IOException;
import java.security.cert.X509Certificate;

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

import org.apache.http.HttpEntity;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.config.Registry;
import org.apache.http.config.RegistryBuilder;
import org.apache.http.conn.socket.ConnectionSocketFactory;
import org.apache.http.conn.socket.PlainConnectionSocketFactory;
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.HttpClientBuilder;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
import org.apache.http.util.EntityUtils;

public class TestApp3 {
	public static void main(String[] args) throws Exception {
		 
       // 设置协议http和https对应的处理socket链接工厂的对象  
       Registry<ConnectionSocketFactory> registry 
       = RegistryBuilder.<ConnectionSocketFactory>create()  
         .register("http", PlainConnectionSocketFactory.INSTANCE)  
         .register("https", trustHttpsCertificates())  
         .build();  
	       
	       PoolingHttpClientConnectionManager connManager = new 
	    		   PoolingHttpClientConnectionManager(registry);  
	       //配置了HttpClients,创建自定义的httpclient对象  
	       HttpClientBuilder builder = HttpClients.custom().setConnectionManager(connManager);  
	  
	       CloseableHttpClient client = builder.build();
		
	        String url="https://www.12306.cn/mormhweb/";
	        HttpGet httpGet=new HttpGet(url);
	        //处理响应部分
	        CloseableHttpResponse response =null;
	        try {
	            response = client.execute(httpGet);
	            HttpEntity entity = response.getEntity();
	            System.out.println("获取到的内容:"+EntityUtils.toString(entity,"UTF-8"));
	            EntityUtils.consume(entity);//关闭entity
	        } catch (Exception e) {
	            e.printStackTrace();
	        } finally{
	            if (client!=null) {
	                try {client.close();} catch (IOException e) {e.printStackTrace();}
	            }
	            if (response!=null) {
	                try {response.close();} catch (IOException e) {e.printStackTrace();}
	            }
	        }
	}
	//创建并返回SSLConnectionSocketFactory对象
	public static SSLConnectionSocketFactory trustHttpsCertificates() throws Exception {  
		SSLConnectionSocketFactory socketFactory = null;  
        TrustManager[] trustAllCerts = new TrustManager[1];  
        TrustManager tm = new myTM();  
        trustAllCerts[0] = tm;  
        SSLContext sc = null;  
        try {  
            sc = SSLContext.getInstance("TLS");  
            sc.init(null, trustAllCerts, null);  
            socketFactory = new SSLConnectionSocketFactory(sc, NoopHostnameVerifier.INSTANCE);  
        } catch (Exception e) {  
            e.printStackTrace();  
        }  
        return socketFactory;  
	}  
   static class myTM implements TrustManager, X509TrustManager {  
     
        public X509Certificate[] getAcceptedIssuers() {  
            return null;  
        }  
          
        public void checkServerTrusted(X509Certificate[] certs, String authType) {  
              
        }  
          
        public void checkClientTrusted(X509Certificate[] certs, String authType) {  
               
        }  
    }  
}

我们在这个类里面写好了绕过ssl验证的方法,再来运行一下访问12306:

 

可以了,已经访问成功了。

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值