这个问题是在生产环境调整之后出现的,因为之前是好使的,后来又一天突然不好使了,观察日志发现代码抛异常,感觉是没有连接上服务器,但是其他环境是好使的,有点疑惑,分析后发现可能是ssl的协议问题,所以观察了下Nginx的配置,发现运维伙伴基于公司的安全机制,将ssl_protocols从 TLSv1.2 TLSv1.1 TLSv1.0; 调整成了TLSv1.2 TLSv1.1; 然后查了下资料,发现jdk的各个版本对ssl协议的默认支持是不一样的,代码里面写的是:
SSLContext sslContext = SSLContext.getInstance("SSL","SunJSSE");
这个说白了用的是当前JDK版本的默认协议,我当前用的是JDK1.7所以JDK1.7默认使用的是TLSv1.0,虽然JDK1.7也支持TLSv1.2 TLSv1.1但是默认使用的并不是这两个,因此我这边调整了下代码,用三种协议挨个去连接,谁链接成功就用谁,代码如下:
if (buildHttpsConn(map, "TLSv1") || buildHttpsConn(map, "TLSv1.1")|| buildHttpsConn(map, "TLSv1.2")) {
// 获取封装在map中的链接对象
httpsConn = (HttpsURLConnection) map.get("httpsConn");
// 取得该连接的输入流,以读取响应内容
insr = new InputStreamReader(httpsConn.getInputStream());
// 读取服务器的响应内容并显示
int respInt;
respInt = insr.read();
while (respInt != -1){
sb.append((char) respInt);
respInt = insr.read();
}
data = sb.toString();
}
/**
* 获取httpsConn链接
* @param map (url,httpsConn)
* @param protocol 协议
* @return
*/
private boolean buildHttpsConn(Map<String, Object> map, String protocol){
try {
URL url = (URL) map.get("url");
//创建SSLContext对象,并使用我们指定的信任管理器初始化
TrustManager[] tm = {new MyX509TrustManager ()};
SSLContext sslContext = SSLContext.getInstance(protocol);
sslContext.init(null, tm, new java.security.SecureRandom());
//从上述SSLContext对象中得到SSLSocketFactory对象
SSLSocketFactory ssf = sslContext.getSocketFactory();
// 创建HttpsURLConnection对象,并设置其SSLSocketFactory对象
HttpsURLConnection httpsConn = (HttpsURLConnection) url.openConnection();
//创建HttpsURLConnection对象,并设置其SSLSocketFactory对象
httpsConn.setSSLSocketFactory(ssf);
LOGGER.info("开始建立https链接使用{}协议", protocol);
httpsConn.getResponseCode();
map.put("httpsConn", httpsConn);
} catch (Exception e) {
LOGGER.error("建立https链接使用{}协议无效!", protocol);
return false;
}
return true;
}
问题得到了解决,下面介绍一下JDK各个版本默认支持的协议,以及他本身支持哪些协议。