错误
javax.net.ssl.SSLHandshakeException: No negotiable cipher suite
at sun.security.ssl.ClientHello$ClientHelloKickstartProducer.produce(ClientHello.java:541)
at sun.security.ssl.SSLHandshake.kickstart(SSLHandshake.java:509)
at sun.security.ssl.ClientHandshakeContext.kickstart(ClientHandshakeContext.java:110)
at sun.security.ssl.TransportContext.kickstart(TransportContext.java:234)
at sun.security.ssl.SSLSocketImpl.startHandshake(SSLSocketImpl.java:393)
at sun.security.ssl.SSLSocketImpl.startHandshake(SSLSocketImpl.java:372)
at sun.net.www.protocol.https.HttpsClient.afterConnect(HttpsClient.java:587)
at sun.net.www.protocol.https.AbstractDelegateHttpsURLConnection.connect(AbstractDelegateHttpsURLConnection.java:185)
at sun.net.www.protocol.https.HttpsURLConnectionImpl.connect(HttpsURLConnectionImpl.java:167)
情形
如果你的项目符合以下条件并抛错,那么这个解决方案适合你
- 项目启动用到了jar依赖分离模式,即启动时指定-Djava.ext.dirs参数
- 项目用到了org.apache.http.impl.client包中的内容,即发送网络请求
- 请求的网络地址为https协议
原因
-Djava.ext.dirs是通过设置系统属性的方式也加载jar包的,他会会覆盖Java本身的ext设置,如果您的程序没有指定该系统属性(-Djava.ext.dirs=xxx)那么该加载器默认加载%JAVA_HOME%/jre/lib/ext目录下的所有jar文件。但如果你手动指定系统属性且忘了把%JAVA_HOME%/jre/lib/ext路径给加上,那么程序不会去加载%JAVA_HOME%/lib/ext下面的jar文件,这意味着你将失去一些功能,例如java自带的加解密算法实现。到这里,您应该明白了为什么会抛错,因为https协议涉及到SSL证书的加解密,而不加载java自带的ext目录无法实现,所以会抛错
解决
知道原因后,解决就简单了,方案有两个(推荐第二个):
- 将所有程序依赖的jar拷贝到%JAVA_HOME%/jre/lib/ext中,启动程序时不指定-Djava.ext.dirs参数,此方案不推荐,这样jdk就只能为一个程序服务,丢失了隔离性,可能会导致一台服务器上的其它程序无法使用
- -Djava.ext.dirs属性配置多个目录,实例: java -jar -Djava.ext.dirs=目录1:目录2…,例如:java -jar -Djava.ext.dirs=./lib:/usr/lib/jdk1.8.0/jre/lib/ext xxx.jar