尽管使用 OkHttpClient 并将 retryOnConnectionFailure 设置为 true(默认),但可能导致 SocketConnection 异常的原因是什么?我们在 Kotlin 中使用 okHttpClientVersion = "4.10.0" 并引入了一个拦截器来在服务器 IP 更改时关闭套接字连接。多个调用并行运行,如果拦截器关闭一个连接中的套接字,则正在进行的所有其他连接都会失败,从而导致 SocketException。
根据文档(https://www.javadoc.io/doc/com.squareup.okhttp3/okhttp/3.0.1/okhttp3/OkHttpClient.Builder.html#retryOnConnectionFailure-boolean-),如果它看到陈旧的池连接。因此,它应该重试并在下一次重试时获得一个新的套接字连接,并且它应该可以工作。但是,我们仍然收到 SocketConnection 异常。是什么导致了这个问题?
如果您在使用 OkHttp 时遇到 SocketException 错误,这可能是由于连接在关闭后没有从连接池中正确删除。
OkHttp内部管理连接和路由,有一个连接池可以复用连接。当使用
connection.socket().close()
关闭连接时,它不会自动从连接池中删除。如果这个关闭的连接后来被重用,OkHttp 会抛出一个 SocketException 错误。
要解决此问题,您需要从连接池中删除已关闭的连接。一种方法是调用
connectionPool.evictAll()
从池中删除所有连接。但是,如果您有其他想要保留在池中的活动连接,这可能并不理想。
另一种方法是使用连接拦截器在关闭后从池中删除关闭的连接。这是一个从池中删除关闭连接的示例拦截器:
class ConnectionPoolCleanupInterceptor implements Interceptor {
private final ConnectionPool connectionPool;
public ConnectionPoolCleanupInterceptor(ConnectionPool connectionPool) {
this.connectionPool = connectionPool;
}
@Override public Response intercept(Chain chain) throws IOException {
// Call the next interceptor in the chain
Response response = chain.proceed(chain.request());
// Remove the connection from the pool if it's closed
if (response.body() != null && response.body().source().exhausted()) {
connectionPool.evict(chain.connection());
}
return response;
}
}
然后您可以将此拦截器添加到您的 OkHttp 客户端:
OkHttpClient client = new OkHttpClient.Builder()
.connectionPool(new ConnectionPool())
.addInterceptor(new ConnectionPoolCleanupInterceptor(connectionPool))
.build();
有了这个拦截器,关闭的连接会自动从连接池中移除,防止重用关闭的连接导致的SocketException错误。