出现该问题,说明okhttp不支持TLSv1,需要手工开启。
异常详情:
Exception in thread "main" javax.net.ssl.SSLHandshakeException: Server chose TLSv1, but that protocol version is not enabled or not supported by the client.
at sun.security.ssl.ClientHandshaker.serverHello(ClientHandshaker.java:462)
at sun.security.ssl.ClientHandshaker.processMessage(ClientHandshaker.java:207)
at sun.security.ssl.Handshaker.processLoop(Handshaker.java:1037)
at sun.security.ssl.Handshaker.process_record(Handshaker.java:965)
at sun.security.ssl.SSLSocketImpl.readRecord(SSLSocketImpl.java:1064)
at sun.security.ssl.SSLSocketImpl.performInitialHandshake(SSLSocketImpl.java:1367)
at sun.security.ssl.SSLSocketImpl.startHandshake(SSLSocketImpl.java:1395)
at sun.security.ssl.SSLSocketImpl.startHandshake(SSLSocketImpl.java:1379)
at okhttp3.internal.connection.RealConnection.connectTls(RealConnection.kt:367)
at okhttp3.internal.connection.RealConnection.establishProtocol(RealConnection.kt:325)
at okhttp3.internal.connection.RealConnection.connect(RealConnection.kt:197)
at okhttp3.internal.connection.ExchangeFinder.findConnection(ExchangeFinder.kt:235)
一般解决办法:
如果我们知道了对方网站使用的协议是TLSv1
则可以
System.setProperty("jdk.tls.client.protocols", "TLSv1");
此时okhttp才会报出他真正的异常
具体异常:
Exception in thread "main" java.net.UnknownServiceException: Unable to find acceptable protocols. isFallback=false, modes=[ConnectionSpec(cipherSuites=[TLS_AES_128_GCM_SHA256, TLS_AES_256_GCM_SHA384, TLS_CHACHA20_POLY1305_SHA256, TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256, TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256, TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384, TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384, TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256, TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256, TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA, TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA, TLS_RSA_WITH_AES_128_GCM_SHA256, TLS_RSA_WITH_AES_256_GCM_SHA384, TLS_RSA_WITH_AES_128_CBC_SHA, TLS_RSA_WITH_AES_256_CBC_SHA, SSL_RSA_WITH_3DES_EDE_CBC_SHA], tlsVersions=[TLS_1_3, TLS_1_2], supportsTlsExtensions=true), ConnectionSpec()], supported protocols=[TLSv1]
at okhttp3.internal.connection.ConnectionSpecSelector.configureSecureSocket(ConnectionSpecSelector.kt:63)
at okhttp3.internal.connection.RealConnection.connectTls(RealConnection.kt:361)
at okhttp3.internal.connection.RealConnection.establishProtocol(RealConnection.kt:325)
at okhttp3.internal.connection.RealConnection.connect(RealConnection.kt:197)
at okhttp3.internal.connection.ExchangeFinder.findConnection(ExchangeFinder.kt:235)
at okhttp3.internal.connection.ExchangeFinder.findHealthyConnection(ExchangeFinder.kt:108)
at okhttp3.internal.connection.ExchangeFinder.find(ExchangeFinder.kt:76)
at okhttp3.internal.connection.RealCall.initExchange$okhttp(RealCall.kt:245)
at okhttp3.internal.connection.ConnectInterceptor.intercept(ConnectInterceptor.kt:32)
at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.kt:100)
at okhttp3.internal.cache.CacheInterceptor.intercept(CacheInterceptor.kt:82)
at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.kt:100)
at okhttp3.internal.http.BridgeInterceptor.intercept(BridgeInterceptor.kt:83)
at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.kt:100)
at okhttp3.internal.http.RetryAndFollowUpInterceptor.intercept(RetryAndFollowUpInterceptor.kt:74)
at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.kt:100)
at okhttp3.internal.connection.RealCall.getResponseWithInterceptorChain$okhttp(RealCall.kt:197)
at okhttp3.internal.connection.RealCall.execute(RealCall.kt:148)
这个其实就是他高版本关闭了对TLSv1的支持,所以会出现问题。以上两个异常都可以通过设置okhttp的模式来进行规避
//设置为兼容模式
ConnectionSpec spec = new ConnectionSpec.Builder(ConnectionSpec.COMPATIBLE_TLS).build();
OkHttpClient.Builder httpBuilder = new OkHttpClient.Builder()
.connectTimeout(10000, TimeUnit.MILLISECONDS)
.readTimeout(10000, TimeUnit.MILLISECONDS)
.writeTimeout(10000, TimeUnit.MILLISECONDS)
.connectionPool(new ConnectionPool(5, 5, TimeUnit.SECONDS))
//构建时指定
.connectionSpecs(Collections.singletonList(spec))
.sslSocketFactory(SSLSocketClient.getSSLSocketFactory(), (X509TrustManager) SSLSocketClient.getTrustManager()[0])
.hostnameVerifier(SSLSocketClient.getHostnameVerifier())
.retryOnConnectionFailure(false);
PS:网上在解决Server chose TLSv1, but that protocol version is not enabled or not supported by the client这个问题时,大部分答案会要求更换okhttp版本,感觉应该就是他的默认模式是否兼容模式,如果是兼容模式,那应该就没问题了。