当web项目在tomcat中启动时,可以正确得建立https链接,发起请求并获得响应。
但是把web项目放到手机上使用i-jetty启动时,发起https请求失败。
检查后发现在建立SSLContext时报错:java.security.NoSuchProviderException: SunJSSE
建立SSLContext的代码为:
- SSLContext sslContext = SSLContext.getInstance("SSL",”SunJSSE”);
查看JDK API:
getInstance
public static SSLContext getInstance(String protocol, String provider) throws NoSuchAlgorithmException, NoSuchProviderException返回实现指定安全套接字协议的
SSLContext
对象。
返回一个封装 SSLContextSpi 实现的新 SSLContext 对象,该实现取自指定的提供者。指定的提供者必须在安全提供者列表中注册。
注意,可以通过 Security.getProviders()
方法获取已注册提供者列表。
protocol
- 所请求协议的标准名称。有关标准协议名称的信息,请参见 Java Secure Socket Extension Reference Guide 的附录 A。
provider
- 提供者的名称。
返回:新的
SSLContext
对象。
抛出:
NoSuchAlgorithmException
- 如果不能从指定提供者获得指定协议的 SSLContextSpi 实现。
NoSuchProviderException
- 如果指定提供者未在安全提供者列表中注册。
IllegalArgumentException
- 如果提供者的名称为 null 或空。
另请参见:
Provider
所以报错的原因应该是”SunJSSE“在Android环境下是没有注册的提供者,所以无法建立SSLContext。
继续查看JDK API,发现:
getInstance
public static SSLContext getInstance(String protocol) throws NoSuchAlgorithmException返回实现指定安全套接字协议的
SSLContext
对象。
此方法从首选提供者开始遍历已注册安全提供者列表。返回一个封装 SSLContextSpi 实现的新 SSLContext 对象,该实现取自支持指定协议的第一个提供者。
注意,可以通过 Security.getProviders()
方法获取已注册提供者列表。
protocol
- 所请求协议的标准名称。有关标准协议名称的信息,请参见 Java Secure Socket Extension Reference Guide 的附录 A。
返回:新的
SSLContext
对象。
抛出:
NoSuchAlgorithmException
- 如果没有提供者支持指定协议的 TrustManagerFactorySpi 实现。
另请参见:
Provider
所以代码改为:
- SSLContext sslContext = SSLContext.getInstance("SSL");
这样会自动调用Security.getProviders()获取已经注册的提供者。
java.net.SocketException: java.security.NoSuchAlgorithmException
java.net.SocketException: java.security.NoSuchAlgorithmException: Error constructing implementation (algorithm: Default, provider: SunJSSE, class: sun.security.ssl.SSLContextImpl$DefaultSSLContext) at javax.net.ssl.DefaultSSLSocketFactory.throwException(SSLSocketFactory.java:198) at javax.net.ssl.DefaultSSLSocketFactory.createSocket(SSLSocketFactory.java:205) at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
服务器从windows移植至linux上突然一些业务不能执行,追踪至抛出来的异常如上。
解决开始:
定位:
问题确实是如上的异常,本地一切正常访问,windows一切正常访问
检测是否为代码问题,是否有平台兼容性问题
此访问为http的post的请求,不访问文件,不查询数据库,请求统一为utf-8不涉及编码问题,暂时排除代码问题
检测是否平台环境问题
j通过搜索发现问java环境问题
解决:
java使用yum安装未设置java环境变量,但java -version正常执行
开始设置环境变量,设置完成 仍不能正常工作
配置并指定sunjce_provider.jar和jce.jar的classpath路径
$JAVA_HOME/lib/ext/sunjce_provider.jar:$JAVA_HOME/lib/jce.jar
并在security/java.security文件设置
security.provider.1=com.sun.crypto.provider.SunJCE
security.provider.2=sun.security.provider.Sun
security.provider.3=sun.security.rsa.SunRsaSign
security.provider.4=sun.security.ec.SunEC
security.provider.5=com.sun.net.ssl.internal.ssl.Provider
security.provider.6=sun.security.jgss.SunProvider
security.provider.7=com.sun.security.sasl.Provider
security.provider.8=org.jcp.xml.dsig.internal.dom.XMLDSigRI
security.provider.9=sun.security.smartcardio.SunPCSC
完成后,重新启动服务,问题依旧
再搜索 从官网上下载 并替换security下 local_policy.jar 和 US_export_policy.jar
完成后,重新启动服务,问题依旧
百思不得其解,于是对比了本地的JRE下项目所引用的jar包,发现和服务器JRE的lib/ext下少包,于是复制jaccess.jar、sunec.jar和sunmscapi.jar至服务器JRE下lib/ext
下。问题解决。
总结:首先,需要错误的正确定位,再次,确认真正引起错误的原因
还有,不了解HttpClient的功能
http://blog.csdn.net/liuyanghai/article/details/7191537
参考下面一段话:
产出密钥时经常会出现java.security.NoSuchAlgorithmException异常。如下面代码,在elipse中编译通过,但运行时会抛出java.security.NoSuchAlgorithmException异常
KeyGenerator keyGen=null;
keyGen = KeyGenerator.getInstance("DES");
keyGen.init(56);
Key key = keyGen.generateKey();
网上关于这个问题的解答不多,已有的一般是说java.security.Provider
是个abstract class,sun没有将它实现,就像jdbc一样由提供商提供;还有就是说关于密钥这一块USA对我们封锁,我们下的jdk里不带;还有就是说要往%javahome%/lib/security/java.security里添加security.provider.1=com.sun.crypto.provider.SunJCE;要确保在classpath里能找到com.sun.crypto.provider.SunJCE;用IBMJDK1.4就没有问题。
根据jdk的文档,从1.4开始就把jce集成起来了,而且在%javahome%/lib/ext里的确存在sunjce_provider.jar,里面包含了com.sun.crypto.provider.SunJCE。在elipse里运行时抛出异常的原因是,class在eclipse里运行时,是通过eclipse的进行classload时会把com.sun.crypto.provider.SunJCE的签名信息去掉,这样JCE就不认这个类了,导致找不到Provider的实现,解决办法:在eclipse的preferences->java->installed jres里选择你指定的jre,edit,将Use default system libraries选上就可以正常运行了。其实把上面的程序在eclipse里编译好,直接在命令行下run,是不会出现上面的问题的。
在eclipse里,IBMjdk可以正常使用,可能是他们密切关系的原因吧,呵呵!
在其它的一些情况下抛出java.security.NoSuchAlgorithmException的话,也可以考虑是不是在通过其它的程序进行classload时去掉了签名