HttpClient:绕开https证书(三)

HTTP 协议可能是现在 Internet 上使用得最多、最重要的协议了,越来越多的 Java 应用程序需要直接通过 HTTP 协议来访问网络资源。虽然在 JDK 的 java.net 包中已经提供了访问 HTTP 协议的基本功能,但是对于大部分应用程序来说,JDK 库本身提供的功能还不够丰富和灵活。HttpClient 是 Apache Jakarta Common 下的子项目,用来提供高效的、最新的、功能丰富的支持 HTTP 协议的客户端编程工具包,并且它支持 HTTP 协议最新的版本和建议。HttpClient 已经应用在很多的项目中,比如 Apache Jakarta 上很著名的另外两个开源项目 Cactus 和 HTMLUnit 都使用了 HttpClient。

当前官网最新版介绍页是:Apache HttpComponents – HttpClient Overview

使用HttpClient发送请求、接收响应很简单,一般需要如下几步即可:

  1. 创建CloseableHttpClient对象。
  2. 创建请求方法的实例,并指定请求URL。如果需要发送GET请求,创建HttpGet对象;如果需要发送POST请求,创建HttpPost对象。
  3. 如果需要发送请求参数,可可调用setEntity(HttpEntity entity)方法来设置请求参数(包括body参数)。setParams方法已过时(4.4.1版本)。
  4. 调用HttpGet、HttpPost对象的setHeader(String name, String value)方法设置header信息,或者调用setHeaders(Header[] headers)设置一组header信息(addHeader也可以,但是set更好,因为set会去重)。
  5. 调用CloseableHttpClient对象的execute(HttpUriRequest request)发送请求,该方法返回一个CloseableHttpResponse。
  6. 调用HttpResponse的getEntity()方法可获取HttpEntity对象,该对象包装了服务器的响应内容。程序可通过该对象获取服务器的响应内容;调用CloseableHttpResponse的getAllHeaders()、getHeaders(String name)等方法可获取服务器的响应头。
  7. 释放连接。无论执行方法是否成功,都必须释放连接

使用https就需要重新构建sslContext对象,把证书塞进去(因为可以改变策略的地方叫较多,很多人一开始被搞得晕头转向,不如全围绕sslContext来构建)

// 构建一个新的证书管理器,重写本该校验的方法,空的就行
public class AlltrustManager implements X509TrustManager {
    @Override
    public void checkClientTrusted(X509Certificate[] x509Certificates, String s) throws CertificateException {
    
    }
    
    @Override
    public void checkServerTrusted(X509Certificate[] x509Certificates, String s) throws CertificateException {
    
    }
    
    @Override
    public X509Certificate[] getAcceptedIssuers() {
        return new X509Certificate[0];
    }
}

写一个https的工具类:



import org.apache.http.HttpResponse;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.methods.HttpPost;
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.SSLConnectionSocketFactory;
import org.apache.http.entity.ByteArrayEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
import sun.misc.JavaSecurityAccess;

import javax.net.ssl.SSLContext;
import javax.net.ssl.X509TrustManager;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.security.KeyManagementException;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import java.util.Map;
import java.util.logging.Logger;

public class HttpUtils {
    
    private static Logger logger = Logger.getLogger("HttpUtils.class");
    
    public static SSLContext createIgnoreVerifySSL() throws NoSuchAlgorithmException, KeyManagementException {
       //关键就是这个sslcontext
        SSLContext context = SSLContext.getInstance("SSLv3");
        X509TrustManager[] alltrustManager = new X509TrustManager[0];
        context.init(null,alltrustManager, new SecureRandom() );
        return context;
    }
    
    public static  String  doPostRequest(String url, Map<String,String> headers,String requestBody) throws NoSuchAlgorithmException, KeyManagementException {
        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);
        connManager.setMaxTotal(200);//最大连接数
        connManager.setDefaultMaxPerRoute(100);//单个服务并发数
        HttpClients.custom().setConnectionManager(connManager);
        //创建自定义的httpclient对象
        CloseableHttpClient client = HttpClients.custom().setConnectionManager(connManager).build();
        //创建post方式请求对象
        HttpPost httpPost = new HttpPost(url);
        //添加header
        if (headers!=null){
            for (Map.Entry<String, String> entry : headers.entrySet()) {
                httpPost.setHeader(entry.getKey(), entry.getValue());
            }
        }
        //添加body
        ByteArrayEntity entity = null;
        try {
            entity = new ByteArrayEntity(requestBody.getBytes("UTF-8"));
            entity.setContentType("application/json");
        } catch (UnsupportedEncodingException e) {
            logger.info("向服务器承保接口发起http请求,封装请求body时出现异常"+e);
            throw new RuntimeException("向服务器承保接口发起http请求,封装请求body时出现异常", e);
        }
        httpPost.setEntity(entity);
        //执行post请求
        HttpResponse response = null;
        try {
            response = client.execute(httpPost);
        } catch (IOException e) {
            logger.info("提交给服务器的请求,不符合HTTP协议"+ e);
            throw new RuntimeException("提交给服务器的请求,不符合HTTP协议", e);
        }
        logger.info("状态码:" + response.getStatusLine());
        return response.toString();
    }
    
    
    
    }

如果不想重写接口,也可以单独构造:

/** 
* 绕过验证 
*   
* @return 
* @throws NoSuchAlgorithmException  
* @throws KeyManagementException  
*/  
public static SSLContext createIgnoreVerifySSL() throws NoSuchAlgorithmException, KeyManagementException {  
        SSLContext sc = SSLContext.getInstance("SSLv3");  

        // 实现一个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;  
            }  
        };  

        sc.init(null, new TrustManager[] { trustManager }, null);  
        return sc;  
    }

然后来验证一下:

public final static void main(String[] args) throws Exception {

        String body = "";

        //采用绕过验证的方式处理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); 

        //创建自定义的httpclient对象  
        CloseableHttpClient client = HttpClients.custom().setConnectionManager(connManager).build();  
        //CloseableHttpClient client = HttpClients.createDefault();

        try{
            //创建post方式请求对象  
            HttpPost httpPost = new HttpPost("https://api.douban.com/v2/book/1220562"); 


            //指定报文头Content-type、User-Agent
            httpPost.setHeader("Content-type", "application/x-www-form-urlencoded");  

            httpPost.setHeader("User-Agent", "Mozilla/5.0 (Windows NT 6.1; rv:6.0.2) Gecko/20100101 Firefox/6.0.2");


            //执行请求操作,并拿到结果(同步阻塞)  
            CloseableHttpResponse response = client.execute(httpPost);  

            //获取结果实体  
            HttpEntity entity = response.getEntity(); 
            if (entity != null) {  
                //按指定编码转换结果实体为String类型  
                body = EntityUtils.toString(entity, "UTF-8");  
            }  

            EntityUtils.consume(entity);  
            //释放链接  
            response.close(); 
            System.out.println("body:" + body);
        }finally{
            client.close();
        }
    }

如果要使用自己的证书呢?

  sslcontext = SSLContexts
                    .custom()
                    .loadTrustMaterial(
                            new File("D://https//ca//cl.jks"),
                            "123456".toCharArray(),
                            new TrustSelfSignedStrategy()).build();

具体可参考此文:http://www.javashuo.com/article/p-ooekqaim-e.html

参考:

使用HttpClient链接池进行https单双向验证 - JavaShuo

使用HttpClient发起请求时将参数放入requestBody中_weixin_33721344的博客-CSDN博客

轻松把玩HttpClient之配置ssl,采用绕过证书验证实现https_崔成龙 . 勇往直前-CSDN博客

HttpClient配置SSL绕过https证书_irokay的专栏-CSDN博客

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值