最近做应用分享微博到新浪和腾讯的后台服务支撑的时候,发现一个问题,应用打成jar包的时候,部署到linux环境下,在请求腾讯https://open.t.qq.com/cgi-bin/request_token校验的时候后台服务抛出了SSLException:
java.lang.Exception: javax.net.ssl.SSLException: Server key
at com.tencent.weibo.utils.QHttpClient.httpGet(QHttpClient.java:65)
at com.tencent.weibo.utils.OAuthClient.requestToken(OAuthClient.java:50)
at com.test.QQTest.requestToken(QQTest.java:37)
at com.test.QQTest.main(QQTest.java:26)
Caused by: javax.net.ssl.SSLException: Server key
at com.sun.net.ssl.internal.ssl.Handshaker.throwSSLException(Handshaker.java:850)
at com.sun.net.ssl.internal.ssl.ClientHandshaker.processMessage(ClientHandshaker.java:150)
at com.sun.net.ssl.internal.ssl.Handshaker.processLoop(Handshaker.java:516)
at com.sun.net.ssl.internal.ssl.Handshaker.process_record(Handshaker.java:454)
at com.sun.net.ssl.internal.ssl.SSLSocketImpl.readRecord(SSLSocketImpl.java:884)
at com.sun.net.ssl.internal.ssl.SSLSocketImpl.performInitialHandshake(SSLSocketImpl.java:1096)
at com.sun.net.ssl.internal.ssl.SSLSocketImpl.writeRecord(SSLSocketImpl.java:623)
at com.sun.net.ssl.internal.ssl.AppOutputStream.write(AppOutputStream.java:59)
at java.io.BufferedOutputStream.flushBuffer(BufferedOutputStream.java:65)
at java.io.BufferedOutputStream.flush(BufferedOutputStream.java:123)
at org.apache.commons.httpclient.HttpConnection.flushRequestOutputStream(HttpConnection.java:828)
at org.apache.commons.httpclient.HttpMethodBase.writeRequest(HttpMethodBase.java:2116)
at org.apache.commons.httpclient.HttpMethodBase.execute(HttpMethodBase.java:1096)
at org.apache.commons.httpclient.HttpMethodDirector.executeWithRetry(HttpMethodDirector.java:398)
at org.apache.commons.httpclient.HttpMethodDirector.executeMethod(HttpMethodDirector.java:171)
at org.apache.commons.httpclient.HttpClient.executeMethod(HttpClient.java:397)
at org.apache.commons.httpclient.HttpClient.executeMethod(HttpClient.java:323)
at com.tencent.weibo.utils.QHttpClient.httpGet(QHttpClient.java:53)
... 3 more
Caused by: java.security.InvalidKeyException: No installed provider supports this key: sun.security.rsa.RSAPublicKeyImpl
at java.security.Signature$Delegate.chooseProvider(Signature.java:1056)
at java.security.Signature$Delegate.engineInitVerify(Signature.java:1088)
at java.security.Signature.initVerify(Signature.java:420)
at com.sun.net.ssl.internal.ssl.HandshakeMessage$DH_ServerKeyExchange.<init>(HandshakeMessage.java:773)
at com.sun.net.ssl.internal.ssl.ClientHandshaker.processMessage(ClientHandshaker.java:145)
... 19 more
Caused by: java.security.NoSuchAlgorithmException: NONEwithRSA Signature not available
at java.security.Signature.getInstance(Signature.java:193)
at com.sun.net.ssl.internal.ssl.JsseJce.getSignature(JsseJce.java:197)
at com.sun.net.ssl.internal.ssl.RSASignature.<init>(RSASignature.java:45)
at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:39)
at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:27)
at java.lang.reflect.Constructor.newInstance(Constructor.java:513)
at java.lang.Class.newInstance0(Class.java:355)
at java.lang.Class.newInstance(Class.java:308)
at java.security.Provider$Service.newInstance(Provider.java:1221)
at java.security.Signature$Delegate.newInstance(Signature.java:938)
at java.security.Signature$Delegate.chooseProvider(Signature.java:1032)
... 23 more
但是将其打成war包部署到tomcat中时,向腾讯发起请求的话就会正常交互;(明明一个纯后台的东西,还得跑到tomcat下,很不爽...)
百度找到一个解决办法,将https://open.t.qq.com/cgi-bin/request_token该成http://open.t.qq.com/cgi-bin/request_token,不过这样就要修改腾讯SDK的源码了;
接着调试新浪的API接口,结果直接抛空指针异常:
Exception in thread "main" java.lang.NullPointerException
at weibo4android.http.BASE64Encoder.encode(BASE64Encoder.java:46)
at weibo4android.http.OAuth.generateSignature(OAuth.java:161)
at weibo4android.http.OAuth.generateAuthorizationHeader(OAuth.java:85)
at weibo4android.http.OAuth.generateAuthorizationHeader(OAuth.java:125)
at weibo4android.http.HttpClient.setHeaders(HttpClient.java:715)
at weibo4android.http.HttpClient.httpRequest(HttpClient.java:607)
at weibo4android.http.HttpClient.httpRequest(HttpClient.java:591)
at weibo4android.http.HttpClient.getOauthRequestToken(HttpClient.java:166)
at weibo4android.Weibo.getOAuthRequestToken(Weibo.java:1567)
at com.test.SinaTest.requestToken(SinaTest.java:57)
at com.test.SinaTest.main(SinaTest.java:34)
查看其SDK源码,发现at weibo4android.http.OAuth.generateSignature(OAuth.java:161)时
执行Mac mac = Mac.getInstance(HMAC_SHA1);的时候直接抛出异常了,其竟然没做任何处理...
} catch (NoSuchAlgorithmException ignore) {
// should never happen
}
将异常打印出来发现:
java.security.NoSuchAlgorithmException: Algorithm HmacSHA1 not available
at javax.crypto.Mac.getInstance(DashoA13*..)
at weibo4android.http.OAuth.generateSignature(OAuth.java:139)
at weibo4android.http.OAuth.generateAuthorizationHeader(OAuth.java:85)
at weibo4android.http.OAuth.generateAuthorizationHeader(OAuth.java:125)
at weibo4android.http.HttpClient.setHeaders(HttpClient.java:715)
at weibo4android.http.HttpClient.httpRequest(HttpClient.java:607)
at weibo4android.http.HttpClient.httpRequest(HttpClient.java:591)
at weibo4android.http.HttpClient.getOauthRequestToken(HttpClient.java:166)
at weibo4android.Weibo.getOAuthRequestToken(Weibo.java:1567)
at com.test.SinaTest.requestToken(SinaTest.java:57)
at com.test.SinaTest.main(SinaTest.java:34)
继续百度,找到一个参考资料http://stackoverflow.com/questions/2856248/nosuchalgorithmexception-algorithm-hmacsha1-not-available
照着做,在sinaSDK源码Mac mac = Mac.getInstance(HMAC_SHA1);前加入
java.security.Security.addProvider(new com.sun.crypto.provider.SunJCE());
然后将sunjce_provider.jar 考到lib下,sunjce_provider.jar 原来位于
$JAVA_HOME/jre/lib/ext
下;
然后执行,ok,没问题了~~
思考~~~why??继续咬牙看上面的参考资料http://stackoverflow.com/questions/2856248/nosuchalgorithmexception-algorithm-hmacsha1-not-available里面的回答;
回答的哥们说可能是$JAVA_HOME/jre/lib、security/java.security 中不包含SunJCE的设置,所以需要在代码中添加
java.security.Security.addProvider(new com.sun.crypto.provider.SunJCE());
然后又找到一个资料http://chenjianjx.iteye.com/blog/738285;
可是我的java.security 中明明包含了security.provider.4=com.sun.crypto.provider.SunJCE
难道是因为找不到sunjce_provider.jar,即时配置了也不管用的原因?
于是乎,全部代码还原,全部SDK代码还原,只是在lib中添加了sunjce_provider.jar,发现所有问题都解决了~~
腾讯API的SSLException也没问题了~~
ok,说了这么多,就是因为缺少sunjce_provider.jar的原因,不知道为什么在tomcat中跑时没问题,难道是tomcat启动的时候加载了~~
继续找资料,$JAVA_HOME/jre/lib/ext 中的jar包会在jvm启动的时候自动加载,可是为什么sunjce_provider.jar没有加载?难道是什么时候跳过了$JAVA_HOME/jre/lib/ext 的加载?
看了一下,启动的命令...jre/bin/java -Xms256m -Xmx512m -Dlabel=temp -Djava.ext.dirs=../lib/ com.test.SinaTest &
ok,现在清楚了,在启动的时候将ext.dirs设成了=../lib/,这个时候自然不会继续加载了~~
(为什么要这样写呢,因为之前某个哥们在lib下放了需要手动改的配置文件~~)