处理https访问时URL.openConnection()返回com.sun.net.ssl.HttpsURLConnection,各位大侠请帮忙看看

KelvenCheung 2011-12-19 09:58:29
测试环境:
JDK 1.4_2 操作系统:win2000 应用服务器:WebSphere 5.1.0

生产环境
JKD 1.6_0_14 操作系统:linux 应用服务器:Jboss

发送https代码如下:


public String postHttps(String urlString, String data, Logger logger) throws Exception {

SSLContext sc = null;
TrustManager[] trustAllCerts = new TrustManager[] { new javax.net.ssl.X509TrustManager() {
public java.security.cert.X509Certificate[] getAcceptedIssuers() {
return null;
}

public void checkClientTrusted(
java.security.cert.X509Certificate[] certs, String authType) {
}

public void checkServerTrusted(
java.security.cert.X509Certificate[] certs, String authType) {
}
} };

try {
sc = SSLContext.getInstance("SSL");
sc.init(null, trustAllCerts, new java.security.SecureRandom());
HttpsURLConnection.setDefaultSSLSocketFactory(sc.getSocketFactory());
} catch (Exception e) {
}

HostnameVerifier hv = new HostnameVerifier() {
public boolean verify(String urlHostName, SSLSession session) {
return urlHostName.equals(session.getPeerHost());
}
};
HttpsURLConnection.setDefaultHostnameVerifier(hv);

OutputStreamWriter os = null;
BufferedReader reader = null;
StringBuffer sb = new StringBuffer();
URL u = new URL(urlString);
HttpsURLConnection conn = (HttpsURLConnection) u.openConnection();
// conn.setRequestProperty("Content-Type", "text/xml");
conn.setDoOutput(true);
conn.setFollowRedirects(true);
// conn.setReadTimeout(30000);
os = new OutputStreamWriter(conn.getOutputStream());
os.write(data);
os.flush();
os.close();

return null;

}



在测试环境是可以正常的发送到指定的https地址上,而在生产环境上访问时会抛出以下错误:
java.lang.ClassCastException:com.sun.net.ssl.internal.www.protocol.https.HttpsURLConnectionOLDImpl cannot be case to javax.net.ssl.HttpsURLConnection.


是在 HttpsURLConnection conn = (HttpsURLConnection) u.openConnection(); 处抛出。


之后用一下页面测试了下:


<%@ page language="java" contentType="text/html; charset=GBK" pageEncoding="GBK"%>
<%@ page import="java.net.*" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=GBK">
<title>测试Https</title>
</head>
<body>
<%
out.print("默认:<br/>");
URL aURL = new URL("https://www.verisign.com");

URLConnection urlConn = aURL.openConnection();
if (urlConn instanceof com.sun.net.ssl.HttpsURLConnection) {
out.print("*** openConnection returns an instanceof com.sun.net.ssl.HttpsURLConnection<br/>");
}

if (urlConn instanceof javax.net.ssl.HttpsURLConnection) {
out.print("*** openConnection returns an instanceof javax.net.ssl.HttpsURLConnection<br/>");
}
if (urlConn instanceof HttpURLConnection) {
out.print("*** openConnection returns an instnace of HttpURLConnection<br/>");
}

%>
</body>
</html>



测试环境输出:
*** openConnection returns an instanceof javax.net.ssl.HttpsURLConnection
*** openConnection returns an instnace of HttpURLConnection
生产环境输出:
*** openConnection returns an instanceof com.sun.net.ssl.HttpsURLConnection
*** openConnection returns an instnace of HttpURLConnection


这就是问题所在,URL.openConnection() 在测试环境返回javax.net.ssl.HttpsURLConnection,而在生产环境则返回:com.sun.net.ssl.HttpsURLConnection

如何能将生产环境URL.openConnection()的返回从com.sun.net.ssl.HttpsURLConnection 变成javax.net.ssl.HttpsURLConnection ?

望做过Https访问的大侠们不吝赐教!

在线等 或联系qq 13386778 万分感谢!
...全文
3183 10 打赏 收藏 转发到动态 举报
写回复
用AI写文章
10 条回复
切换为时间正序
请发表友善的回复…
发表回复
kingwudy 2014-07-01
  • 打赏
  • 举报
回复
这个问题的解决方法: 创建URL时指定Handler(new URL(null, url,new sun.net.www.protocol.https.Handler());)
KelvenCheung 2012-10-09
  • 打赏
  • 举报
回复
原来忘记结贴!
lxbccsu 2011-12-19
  • 打赏
  • 举报
回复
搞错了;JSP只是测试。
你上应该在servlet处理了;
像这种以来具体平台的类,你可提供个工具类来处理:

lxbccsu 2011-12-19
  • 打赏
  • 举报
回复
原因2,3楼说的很清楚了;

你可以这样改下,再测试:

URLConnection = null;
if (urlConn instanceof com.sun.net.ssl.HttpsURLConnection) {
out.print("*** openConnection returns an instanceof com.sun.net.ssl.HttpsURLConnection<br/>");
urlConn = aURL.openConnection();
}

if (urlConn instanceof javax.net.ssl.HttpsURLConnection) {
out.print("*** openConnection returns an instanceof javax.net.ssl.HttpsURLConnection<br/>");
urlConn = aURL.openConnection();
}
if (urlConn instanceof HttpURLConnection) {
out.print("*** openConnection returns an instnace of HttpURLConnection<br/>");
urlConn = aURL.openConnection();
}



kouyiSC 2011-12-19
  • 打赏
  • 举报
回复
引用
As you can see it puts what I think is the old wrong package (at least for Java 1.4+) "com.sun.net.ssl.internal.www.protocol" at the first of the list of handlers. Doing this is not only unnecessary but can cause problems in Java 1.4+ from what I've read and have now experienced.


jdk版本问题。。
http://weblogs.java.net/blog/garysweaver/archive/2008/08/javaprotocolhan_1.html

dracularking 2011-12-19
  • 打赏
  • 举报
回复
javax.net.ssl.HttpsURLConnection
com.sun.net.ssl.HttpsURLConnection
com.sun.net.ssl.internal.www.protocol.https.HttpsURLConnectionOLDImpl

这些类貌似都是在jdk的jsse.jar中,而这个com.sun.net.ssl.HttpsURLConnection应该是deprecated的了,代码都一样吧,仅仅是环境不同,具体实现类的选择貌似视环境而定,感觉是环境高度相关的一个case,能不能先试试把测试环境的jsse.jar换到生成环境中...
iamrf 2011-12-19
  • 打赏
  • 举报
回复
是不是你的生产环境上没有导入证书啊?你需要把证书导入到你java程序所运行的那个JDK里或者JRE里才可以,每换一个新环境或者证书有变更都需要重新导入证书的。

具体的步骤,你得先拿到你要访问的网站证书,用IE访问,在页面上右键-->Properties,点击“Certificates”按钮,Details选项卡中,点击“Copy to file”。拿到证书后,将证书导入到你所用的那个JDK里。

导入证书的步骤:cmd 进入<%JAVA_HOME%>\lib\bin\目录,或者<%JRE_HOME%>\bin\目录(实际看你的服务器运行时用的是哪个jre环境),执行命令:keytool -importcert -alias 068169 -keystore ..\lib\security\cacerts -file C:\sertificent\10.145.68.169.cer -trustcacerts
keytool.exe是JDK提供的证书导入工具,具体参数含义可以-help自己查一下,值得一提的是keystore和file两个命令,需要指定路径,一个是证书库路径,一个是需要导入的证书路径,两个路径都不能有空格,否则会出错。要么将JRE装到一个没空格的路径下,要么使用相对路径,要么使用<%环境变量%>lib\security\cacerts指定路径,只要保证没空格就行。执行命令,需要提供密码,默认密码是:changeit,这个密码可以进行修改。

证书导入成功后,启动服务,再次访问下应该就OK了。
KelvenCheung 2011-12-19
  • 打赏
  • 举报
回复
开了一下午的会,比写程序还累...

谢谢以上各位的建议/意见,晚一点再在生产网上试一下。
lxbccsu 2011-12-19
  • 打赏
  • 举报
回复
做了点测试,你可以使用反射或直接使用sun.net.www.protocol.http.HttpURLConnection来测试改下:

public static void main(String[] args) throws Exception {
processBySUNPlatform("http://", "", null);
processByReflection(new URL("http://").openConnection(), "", null);
}

public static void processBySUNPlatform(String urlString, String data, Logger logger) throws IOException{
OutputStreamWriter os = null;

URL u = new URL(urlString);
sun.net.www.protocol.http.HttpURLConnection conn = (sun.net.www.protocol.http.HttpURLConnection) u.openConnection();
conn.setDoOutput(true);
com.sun.net.ssl.HttpsURLConnection.setFollowRedirects(true);
os = new OutputStreamWriter(conn.getOutputStream());
os.write(data);
os.flush();
os.close();
}

public static void processByReflection(Object conn, String data, Logger logger) throws Exception{
if(conn == null) return;
OutputStreamWriter os = null;

conn.getClass().getMethod("setDoOutput", boolean.class).invoke(conn, true);
conn.getClass().getMethod("setFollowRedirects", boolean.class).invoke(null, true);
os = new OutputStreamWriter((OutputStream)conn.getClass().getMethod("getOutputStream", null).invoke(conn, null));
os.write(data);
os.flush();
os.close();
}

有点不明白,开发环境、测试环境 和 Production的 JRE和服务器 是不同的?
一个很显然的问题是JRE1.6有很多的新特性在JRE1.4下是不支持的。

81,120

社区成员

发帖
与我相关
我的任务
社区描述
Java Web 开发
社区管理员
  • Web 开发社区
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧