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

2025-08-11 22:19:35

本程序使用的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 registry

= RegistryBuilder.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:

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

掌握Android触控笔,绘画新境界:探索触控笔绘画的无限可能
207年,郭嘉病重难愈、仰屋窃叹而亡,曹操:饮酒好色,不加节制