在过去的几周里,我们的客户开始看到100个这样的“SSLException错误 - 连接重置连接”,我无法弄清楚为什么
public class OkHttpClientProvider implements IOkHttpClientProvider {
OkHttpClient okHttpClient;
public OkHttpClientProvider() {
this.okHttpClient = createClient();
}
public OkHttpClient getOkHttpClient() {
return this.okHttpClient;
}
private OkHttpClient createClient() {
return new OkHttpClient();
}
}
上述客户提供商是单身人士。 RestAdapter是使用这个注入的客户端构建的(我们使用匕首) -
RestAdapter.Builder restAdapterBuilder = new RestAdapter.Builder()
.setConverter(converter)
.setEndpoint(networkRequestDetails.getServerUrl())
.setClient(new OkClient(okHttpClientProvider.getOkHttpClient()))
.setErrorHandler(new NetworkSynchronousErrorHandler(eventBus))
);
基于堆栈溢出解决方案,我发现了 -
我不想禁用keep alive,因为大多数现代客户都不这样做。此外,我们正在使用OkHttp 2.4,这是后冰淇淋三明治设备的一个问题,所以我希望它应该照顾这些潜在的网络问题。 iOS客户端也获得了这些例外但接近100倍(iOS客户端使用AFNetworking 2.0)。我正在努力寻找新的东西,在这一点上尝试,任何帮助/想法?
更新 - 通过okhttp添加完整堆栈跟踪
retrofit.RetrofitError: Read error: ssl=0x9dd07200: I/O error during system call, Connection reset by peer
at retrofit.RestAdapter$RestHandler.invokeRequest(RestAdapter.java:390)
at retrofit.RestAdapter$RestHandler.invoke(RestAdapter.java:240)
at java.lang.reflect.Proxy.invoke(Proxy.java:397)
at $Proxy15.getAccessTokenUsingResourceOwnerPasswordCredentials(Unknown Source)
at com.company.droid.repository.network.NetworkRepository.getAccessTokenUsingResourceOwnerPasswordCredentials(NetworkRepository.java:76)
at com.company.droid.ui.login.LoginTask.doInBackground(LoginTask.java:88)
at com.company.droid.ui.login.LoginTask.doInBackground(LoginTask.java:23)
at android.os.AsyncTask$2.call(AsyncTask.java:292)
at java.util.concurrent.FutureTask.run(FutureTask.java:237)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1112)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:587)
at java.lang.Thread.run(Thread.java:818)
Caused by: javax.net.ssl.SSLException: Read error: ssl=0x9dd07200: I/O error during system call, Connection reset by peer
at com.android.org.conscrypt.NativeCrypto.SSL_read(Native Method)
at com.android.org.conscrypt.OpenSSLSocketImpl$SSLInputStream.read(OpenSSLSocketImpl.java:699)
at okio.Okio$2.read(Okio.java:137)
at okio.AsyncTimeout$2.read(AsyncTimeout.java:211)
at okio.RealBufferedSource.indexOf(RealBufferedSource.java:306)
at okio.RealBufferedSource.indexOf(RealBufferedSource.java:300)
at okio.RealBufferedSource.readUtf8LineStrict(RealBufferedSource.java:196)
at com.squareup.okhttp.internal.http.HttpConnection.readResponse(HttpConnection.java:191)
at com.squareup.okhttp.internal.http.HttpTransport.readResponseHeaders(HttpTransport.java:80)
at com.squareup.okhttp.internal.http.HttpEngine.readNetworkResponse(HttpEngine.java:917)
at com.squareup.okhttp.internal.http.HttpEngine.readResponse(HttpEngine.java:793)
at com.squareup.okhttp.internal.huc.HttpURLConnectionImpl.execute(HttpURLConnectionImpl.java:439)
at com.squareup.okhttp.internal.huc.HttpURLConnectionImpl.getResponse(HttpURLConnectionImpl.java:384)
at com.squareup.okhttp.internal.huc.HttpURLConnectionImpl.getResponseCode(HttpURLConnectionImpl.java:497)
at com.squareup.okhttp.internal.huc.DelegatingHttpsURLConnection.getResponseCode(DelegatingHttpsURLConnection.java:105)
at com.squareup.okhttp.internal.huc.HttpsURLConnectionImpl.getResponseCode(HttpsURLConnectionImpl.java:25)
at retrofit.client.UrlConnectionClient.readResponse(UrlConnectionClient.java:73)
at retrofit.client.UrlConnectionClient.execute(UrlConnectionClient.java:38)
at retrofit.RestAdapter$RestHandler.invokeRequest(RestAdapter.java:321)
at retrofit.RestAdapter$RestHandler.invoke(RestAdapter.java:240)
at java.lang.reflect.Proxy.invoke(Proxy.java:397)
at $Proxy15.getAccessTokenUsingResourceOwnerPasswordCredentials(Unknown Source)
at com.company.droid.repository.network.NetworkRepository.getAccessTokenUsingResourceOwnerPasswordCredentials(NetworkRepository.java:76)
at com.company.droid.ui.login.LoginTask.doInBackground(LoginTask.java:88)
at com.company.droid.ui.login.LoginTask.doInBackground(LoginTask.java:23)
at android.os.AsyncTask$2.call(AsyncTask.java:292)
at java.util.concurrent.FutureTask.run(FutureTask.java:237)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1112)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:587)
at java.lang.Thread.run(Thread.java:818)
]}
最近我在处理一些遗留代码时遇到了这个问题。谷歌搜索后我发现问题无处不在,但没有任何具体的解决方案。我研究了异常消息的各个部分,并在下面进行了分析。
分析:
SSLException
:SSL(安全套接字层)发生异常,它在JDK的javax.net.ssl
包中实现(openJDK/oracleJDK/AndroidSDK
)Read error ssl=# I/O error during system call
:从安全套接字读取时发生错误。它发生在使用本机系统库/驱动程序时。请注意,所有平台solaris,Windows等都有自己的套接字库,SSL使用它们。 Windows使用WINSOCK库。Connection reset by peer
:系统库(Solaris报告ECONNRESET
,Windows报告WSAECONNRESET
)报告此消息,数据传输中使用的套接字不再可用,因为远程主机强制关闭现有连接。需要在主机和客户端之间创建新的安全路径原因:
理解这个问题,我尝试找到连接重置背后的原因,我想出了以下原因:
Network dropped connection on reset(On Windows(WSAENETRESET))
而失败,后续操作因Connection reset by peer(On Windows(WSAECONNRESET))
而失败。解析度:
Connection reset by peer
。Connection reset by peer
。Connection reset by peer
。以下是建议在各种论坛上设置以解决问题的术语
ConnectionTimeout:
仅在进行连接时使用。如果主机需要时间来连接更高的值,则客户端会等待连接。SoTimeout
:套接字超时 - 它表示接收数据包以将连接视为活动的最长时间。如果在给定时间内没有收到数据,则认为连接已停止/已断开。Linger
:当数据排队等待发送并且在套接字上调用close套接字函数时,套接字不应该关闭的时间。TcpNoDelay
:你想要禁用保存和累积TCP数据包的缓冲区,并在达到阈值后发送它们吗?将此设置为true将跳过TCP缓冲,以便立即发送每个请求。网络中的减速可能是由于更小和更频繁的分组传输导致的网络流量增加引起的。因此,上述参数都不能帮助保持网络活跃,从而无效。
我发现一个设置可能有助于解决这个功能的问题
setKeepAlive(true)
setSoKeepalive(HttpParams params, enableKeepalive="true")
我是如何解决我的问题的?
HttpConnectionParams.setSoKeepAlive(params, true)
SSLException
并检查Connection reset by peer
的异常消息我希望细节有所帮助。快乐编码......
如果使用Nginx
并遇到类似的问题,那么这可能会有所帮助:
在此sslTesturl上扫描您的域名,并查看您的设备版本是否允许连接。
如果由于TLS支持而无法连接较低版本的设备(如<Android 4.4.2等),请尝试将此添加到您的Nginx配置文件中,
ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
今天早上我们有同样的问题,并解决了...希望这有助于......
IIS 8上的SSL
希望这可以帮助!!!
Android默认支持SSL实施,但Android N(API级别24)和Android 5.1(API级别22)以下除外 在服务器端实现SSL之后,在API级别22设备之下进行API调用时出现错误;那是在创建OkHttpClient客户端对象时,并通过添加connectionSpecs()方法OkHttpClient.Builder类来修复。
收到的错误是
响应失败:javax.net.ssl.SSLException:SSL握手中止:ssl = 0xb8882c00:系统调用期间的I / O错误,同级连接重置
所以我通过添加支票来修复此问题
if ( Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP_MR1) {
// Do something for below api level 22
List<ConnectionSpec> specsList = getSpecsBelowLollipopMR1(okb);
if (specsList != null) {
okb.connectionSpecs(specsList);
}
}
也适用于Android N(API级别24);我在进行HTTP调用时遇到错误
HTTP FAILED:javax.net.ssl.SSLHandshakeException:握手失败
这是通过添加Android 7的支票来修复的,特别是
if (android.os.Build.VERSION.SDK_INT == Build.VERSION_CODES.N){
// Do something for naugat ; 7
okb.connectionSpecs(Collections.singletonList(getSpec()));
}
所以我的最终OkHttpClient对象将是:
OkHttpClient client
HttpLoggingInterceptor httpLoggingInterceptor2 = new
HttpLoggingInterceptor();
httpLoggingInterceptor2.setLevel(HttpLoggingInterceptor.Level.BODY);
OkHttpClient.Builder okb = new OkHttpClient.Builder()
.addInterceptor(httpLoggingInterceptor2)
.addInterceptor(new Interceptor() {
@Override
public Response intercept(Chain chain) throws IOException {
Request request = chain.request();
Request request2 = request.newBuilder().addHeader(AUTH_KEYWORD, AUTH_TYPE_JW + " " + password).build();
return chain.proceed(request2);
}
}).connectTimeout(30, TimeUnit.SECONDS)
.writeTimeout(30, TimeUnit.SECONDS)
.readTimeout(30, TimeUnit.SECONDS);
if (android.os.Build.VERSION.SDK_INT == Build.VERSION_CODES.N){
// Do something for naugat ; 7
okb.connectionSpecs(Collections.singletonList(getSpec()));
}
if ( Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP_MR1) {
List<ConnectionSpec> specsList = getSpecsBelowLollipopMR1(okb);
if (specsList != null) {
okb.connectionSpecs(specsList);
}
}
//init client
client = okb.build();
getSpecsBelowLollipopMR1函数就像,
private List<ConnectionSpec> getSpecsBelowLollipopMR1(OkHttpClient.Builder okb) {
try {
SSLContext sc = SSLContext.getInstance("TLSv1.2");
sc.init(null, null, null);
okb.sslSocketFactory(new Tls12SocketFactory(sc.getSocketFactory()));
ConnectionSpec cs = new ConnectionSpec.Builder(ConnectionSpec.MODERN_TLS)
.tlsVersions(TlsVersion.TLS_1_2)
.build();
List<ConnectionSpec> specs = new ArrayList<>();
specs.add(cs);
specs.add(ConnectionSpec.COMPATIBLE_TLS);
return specs;
} catch (Exception exc) {
Timber.e("OkHttpTLSCompat Error while setting TLS 1.2"+ exc);
return null;
}
}
Tls12SocketFactory类将在下面的链接中找到(由gotev评论):
https://github.com/square/okhttp/issues/2372
如需更多支持,请在下面添加一些链接,这将对您有所帮助,
https://developer.android.com/training/articles/security-ssl
此错误消息的另一个可能原因是服务器或负载平衡器阻止了HTTP方法。
似乎是standard security practice阻止未使用的HTTP方法。我们遇到了这个问题,因为HEAD被负载均衡器阻止了(但奇怪的是,不是所有的负载均衡服务器,导致它只在某些时候失败)。我能够通过临时更改它以使用GET方法来测试请求本身是否正常工作。
iOS上的错误代码是:请求应用程序代码时出错:错误域= NSURLErrorDomain代码= -1005“网络连接丢失。”