整理异常:PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException:

堆栈错误先贴出来:

org.springframework.web.client.ResourceAccessException: I/O error on POST request for “https的url地址”: sun.security.validator.ValidatorException: PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target; nested exception is 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

Caused by: 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

Caused by: sun.security.validator.ValidatorException: PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification p

我当时的情况是自己的开发环境可以请求到对方的https地址,但是发布到Linux的测试环境后请求不通,报错如上.解决回顾后,觉得当时做的无用功挺多,现在想来按以下步骤确认解决问题会节省很多时间.

1.环境确认

一定要先确定自己的环境中的防火墙,代理,配置正确.从整个大局上分析解决问题.
可以使用curl -k (跳过证书)命令,wget命令等测试自己请求的https地址是否可以在环境中连通.我是使用wget命令提示访问被拒绝wget请求

2.生成证书,导入证书或安装证书

1.生成证书,上传到Linux上,并在代码中引用:
https://blog.csdn.net/i_like1/article/details/80334298
2.从浏览器中下载对应证书,并上传到Linux找那个的jdk环境中:
https://blog.csdn.net/liangcha007/article/details/84661532

3.代码层面改造

restTemplate代码:

import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpEntity;
import org.springframework.web.client.RestTemplate;
import org.springframework.http.ResponseEntity;
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_JSON);
HttpEntity<String> entity = new HttpEntity<>(headers);

RestTemplate restTemplate = new RestTemplate();
restTemplate.setRequestFactory(new HttpComponentsClientHttpRequestFactory());
SslUtils.ignoreSsl();
ResponseEntity<Res> resEntity = restTemplate.postForEntity(url, entity, Res.class);

SslUtils代码:

import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
import javax.net.ssl.HostnameVerifier;
import javax.net.ssl.HttpsURLConnection;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSession;
import javax.net.ssl.TrustManager;
import javax.net.ssl.X509TrustManager;

public class SslUtils {

	public static void trustAllHttpsCertificates() throws Exception {
		TrustManager[] trustAllCerts = new TrustManager[1];
		TrustManager tm = new miTM();
		trustAllCerts[0] = tm;
		SSLContext sc = SSLContext.getInstance("SSL");
		sc.init(null, trustAllCerts, null);
		HttpsURLConnection.setDefaultSSLSocketFactory(sc.getSocketFactory());
	}

	static class miTM implements TrustManager, X509TrustManager {
		@Override
        public X509Certificate[] getAcceptedIssuers() {
			return null;
		}

		public boolean isServerTrusted(X509Certificate[] certs) {
			return true;
		}

		public boolean isClientTrusted(X509Certificate[] certs) {
			return true;
		}

		@Override
        public void checkServerTrusted(X509Certificate[] certs, String authType) throws CertificateException {
			return;
		}

		@Override
        public void checkClientTrusted(X509Certificate[] certs, String authType) throws CertificateException {
			return;
		}
	}

	/**
	 * 忽略HTTPS请求的SSL证书,必须在openConnection之前调用
	 * 
	 * @throws Exception
	 */
	public static void ignoreSsl() throws Exception {
		HostnameVerifier hv = new HostnameVerifier() {
			@Override
            public boolean verify(String urlHostName, SSLSession session) {
				return true;
			}
		};
		trustAllHttpsCertificates();
		HttpsURLConnection.setDefaultHostnameVerifier(hv);
	}
}
  • httpsClient请求(未采纳)
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.HttpStatus;
import org.apache.http.util.EntityUtils;
import com.alibaba.fastjson.JSON;
  Res res = null;
  CloseableHttpClient httpsClient = null;
  try {
      httpsClient = (CloseableHttpClient) HttpClientFactoryWithNoSSL.getHttpsClient();
  } catch (Exception e) {
      e.printStackTrace();
  }
  HttpGet httpGet = new HttpGet(url);

  httpGet.addHeader("Content-Type", "application/json");
  String mem = "";
  CloseableHttpResponse responseMem = null;
  CloseableHttpResponse responseCPU = null;
  CloseableHttpResponse responseDisk = null;
  try {
      responseMem = httpsClient.execute(httpGet);
      if (responseMem.getStatusLine().getStatusCode() != HttpStatus.SC_OK) {
          mem = "0";
      } else {
          org.apache.http.HttpEntity resEntity = responseMem.getEntity();
          if (resEntity != null) {
              mem = EntityUtils.toString(resEntity, "UTF-8");
              res = JSON.parseObject(mem,Res.class);
          }
          EntityUtils.consume(resEntity);//要消耗消息实体,这是必须步骤
      }
  } catch (Exception e1) {
      e1.printStackTrace();
      mem = "0";
  } finally {
      try {
          if(responseMem != null){
              responseMem.close();//尝试关闭资源,将socket连接返回给资源池
          }
      } catch (IOException e) {
          e.printStackTrace();
      }
  }

gradle引入信息,可自行转换成maven格式

compile('org.apache.httpcomponents:httpclient:4.5.3')

所需的HttpClientFactoryWithNoSSL类

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.security.KeyManagementException;
import java.security.KeyStore;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import java.security.cert.CertificateException;
import javax.net.ssl.SSLContext;
import javax.net.ssl.X509TrustManager;
import com.walmart.workwechat.manager.HttpsTrustManager;
import org.apache.http.client.HttpClient;
import org.apache.http.conn.HttpClientConnectionManager;
import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
import org.apache.http.conn.ssl.SSLContexts;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;

public class HttpClientFactoryWithNoSSL {

    private static CloseableHttpClient client;
    //连接池
    private static HttpClientConnectionManager poolingConnManager = new PoolingHttpClientConnectionManager();

    /**
     * 获取不需要ssl认证的httpClient实例
     *
     * @Title: getHttpsClientWithNoCert
     * @Description: TODO
     * @Author: Think
     * @Date :Jan 16, 2019
     * @return: HttpClient
     */
    public static HttpClient getHttpsClient() throws Exception {

        if (client != null) {
            return client;
        }
        SSLContext sslcontext = SSLContexts.custom().useSSL().build();
        sslcontext.init(null, new X509TrustManager[]{new HttpsTrustManager()}, new SecureRandom());
        SSLConnectionSocketFactory factory = new SSLConnectionSocketFactory(sslcontext,
                SSLConnectionSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER);
        client = HttpClients.custom().setConnectionManager(poolingConnManager).setSSLSocketFactory(factory).build();

        return client;
    }

    public static void releaseInstance() {
        client = null;
    }
}
  • httpsClient2请求
import javax.net.ssl.SSLContext;
import org.apache.http.config.Registry;
import org.apache.http.config.RegistryBuilder;
import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.util.EntityUtils;
import java.io.IOException;
import java.security.KeyManagementException;
import java.security.NoSuchAlgorithmException;
        WeChatTokenRes res = null;
        SSLContext sslcontext = null;
        try {
            //设置协议http和https对应的处理socket链接工厂的对象
            sslcontext = createIgnoreVerifySSL();
            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();
            //处理请求参数拼接(参数为json) 如:?name = ""&pwd = ""
            String urlNameString = url;
            //创建get方式请求对象
            HttpGet get = new HttpGet(urlNameString);
            //指定报文头Content-type、User-Agent
            //get.setHeader("Content-type", "application/x-www-form-urlencoded");
            get.setHeader("User-Agent", "Mozilla/5.0 (Windows NT 6.1; rv:6.0.2) Gecko/20100101 Firefox/6.0.2");
            //执行请求操作,并拿到结果(同步阻塞)
            CloseableHttpResponse response = client.execute(get);
            //获取结果实体
            org.apache.http.HttpEntity entity = response.getEntity();
            if (entity != null) {
                //按指定编码转换结果实体为String类型
                String body = EntityUtils.toString(entity, "UTF-8");
                res = JSON.parseObject(body,WeChatTokenRes.class);
                // 返回对外IP信息
                res.setMessage(body);
            }
            EntityUtils.consume(entity);
            //释放链接
            response.close();
        } catch (ClientProtocolException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
        } catch (KeyManagementException e) {
            e.printStackTrace();
        }finally{

        }
        return res;
import javax.net.ssl.SSLContext;
import javax.net.ssl.TrustManager;
import javax.net.ssl.X509TrustManager;
    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) {
            }

            @Override
            public void checkServerTrusted(
                    java.security.cert.X509Certificate[] paramArrayOfX509Certificate,
                    String paramString) {
            }

            @Override
            public java.security.cert.X509Certificate[] getAcceptedIssuers() {
                return null;
            }
        };

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

4.总结

以上从环境,证书,代码三个方面解决报错问题.我最后使用的restTemplate方式请求通过的.以上经验供借鉴参考.

PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target. This error occurs when the SSL certificate of the target server cannot be validated by the Java Virtual Machine (JVM). The JVM is unable to establish a trusted connection because it cannot find a valid certification path. To resolve this issue, you can try the following steps: 1. Update the Java Runtime Environment (JRE) or Java Development Kit (JDK) to the latest version available. This ensures that you have the latest trusted root certificates. 2. Import the SSL certificate of the target server into the Java keystore. You can use the keytool command-line tool to import the certificate. Here's an example command: ``` keytool -importcert -alias server -keystore cacerts -file server.crt ``` Replace "server" with an alias of your choice, "cacerts" with the path to the Java keystore file (usually located in the JRE installation directory), and "server.crt" with the path to the SSL certificate file. 3. If you are using a custom truststore, ensure that it contains all necessary certificates, including any intermediate or root certificates required to establish trust with the target server. 4. If you are running your application behind a proxy server, make sure that the proxy server's SSL certificate is valid and trusted by your JVM. By following these steps, you should be able to resolve the PKIX path building failed error and establish a successful SSL connection.
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值