目录

1. 背景

2. 报错信息

3. 问题分析

4. 解决方法


1. 背景

PCI认证,要求安全传输层协议由之前的TLS v1.0、TLS v1.1升级到TLS v1.2。

2. 报错信息

java.lang.Exception: 接口调用失败:
	at com.huateng.szairpay.common.utils.HTTPSInvoke.sendHttpsRequestByPost(HTTPSInvoke.java:97)
	at com.huateng.szairpay.common.utils.HTTPSInvoke.main(HTTPSInvoke.java:193)
Caused by: java.security.NoSuchAlgorithmException: TLSv SSLContext not available
	at sun.security.jca.GetInstance.getInstance(GetInstance.java:159)
	at javax.net.ssl.SSLContext.getInstance(SSLContext.java:156)
	at com.huateng.szairpay.common.utils.HTTPSInvoke.sendHttpsRequestByPost(HTTPSInvoke.java:70)
	... 1 more

3. 问题分析

经查阅资料,发现jdk1.7是默认采用TLSv1.0版本。如图所示:

4. 解决方法

  • 创建SSLContext实例,明确指定使用TLS协议进行处理: 
SSLContext ctx = SSLContext.getInstance("TLSv1.2");

  • 参考代码
public class HTTPSInvoke {
    private static final Log log = LogFactory.getLog(HTTPSInvoke.class);

    public static String sendHttpsRequestByPost(String url, Map<String, String> params) throws Exception {
        String responseContent = null;
        HttpClient httpClient = new DefaultHttpClient();
        X509TrustManager xtm = new X509TrustManager() {
            public void checkClientTrusted(X509Certificate[] arg0, String arg1) throws CertificateException {
            }
            public void checkServerTrusted(X509Certificate[] arg0, String arg1) throws CertificateException {
            }
            public X509Certificate[] getAcceptedIssuers() {
                return null;
            }
        };
        X509HostnameVerifier hostnameVerifier = new X509HostnameVerifier() {
            public boolean verify(String hostname, SSLSession session) {
                return false;
            }
            public void verify(String arg0, SSLSocket arg1) throws IOException {
            }
            public void verify(String arg0, X509Certificate arg1) throws SSLException {
            }
            public void verify(String arg0, String[] arg1, String[] arg2) throws SSLException {
            }
        };
        try {
            SSLContext ctx = SSLContext.getInstance("TLSv1.2");
            ctx.init(null, new TrustManager[]{xtm}, null);
            SSLSocketFactory socketFactory = new SSLSocketFactory(ctx);
            socketFactory.setHostnameVerifier(hostnameVerifier);
            httpClient.getConnectionManager().getSchemeRegistry().register(new Scheme("https", socketFactory, 443));
            log.info("调用接口:" + url);
            HttpPost httpPost = new HttpPost(url);
            List<NameValuePair> formParams = new ArrayList<NameValuePair>();
            for (Map.Entry<String, String> entry : params.entrySet()) {
                formParams.add(new BasicNameValuePair((String) entry.getKey(), (String) entry.getValue()));
            }
            httpPost.setEntity(new UrlEncodedFormEntity(formParams, "UTF-8"));
            HttpResponse response = httpClient.execute(httpPost);
            HttpEntity entity = response.getEntity();
            if (entity != null) {
                responseContent = EntityUtils.toString(entity, "UTF-8");
            }
        } catch (KeyManagementException e) {
            throw new Exception("接口调用失败:", e);
        } catch (NoSuchAlgorithmException e) {
            throw new Exception("接口调用失败:", e);
        } catch (UnsupportedEncodingException e) {
            throw new Exception("接口调用失败:", e);
        } catch (ClientProtocolException e) {
            throw new Exception("接口调用异常:", e);
        } catch (ParseException e) {
            throw new Exception("接口调用失败:", e);
        } catch (IOException e) {
            throw new Exception("接口调用失败:", e);
        } finally {
            httpClient.getConnectionManager().shutdown();
        }
        return responseContent;
    }
}

Logo

旨在为数千万中国开发者提供一个无缝且高效的云端环境,以支持学习、使用和贡献开源项目。

更多推荐