OkHttpClient: CHECK I/O faults

Problem description

We have a requirement to get the width and height information uploaded to the OSS image, suffix the original file link? X-oss-process =image/info, then use OkHttpClient to assemble the GET request to get the data. When testing in the test environment, an occasional IOException is found

java.io.IOException: unexpected end of stream on Connection{, The proxy = DIRECT hostAddress = cipherSuite = TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 protocol = HTTP / 1.1}

Troubleshoot problems

  1. Search the data to find an explanation for this problem: The error occurs when OkHttp try to reuse a connection that is in FIN_WAIT2 state in server,because the server keep_alive timeout is lesser than the client timeout.

OkHttp reuses a connection that was in FIN_WAIT2 state, causing error 2. When can FIN_WAIT2 state occur in TCP three-way handshake:

The active party initiates a FIN packet and waits for the FIN packet to be sent. If no FIN packet is sent (the active party is in CLOSE_WAIT state with data to be sent, etc.), the active party will be in FIN_WAIT2 state. The active party may be in FIN_WAIT2 forever

Problem solving

1. The first solution:

If a client uses the http1.1 protocol and does not want to use long links, the header must be set to close. If the server side also does not want to support long links, the value of connection should also be specified as close in response. Whether the header of request or Response contains a connection with a value of close, it indicates that the TCP connection currently in use will be broken after the request is processed. The client must create a new TCP link when making a new request.

2. Second solution:

Set retryOnConnectionFailure=true to allow reconnection if the connection fails

OkHttpClient.Builder()
      .sslSocketFactory(sslSocketFactory(), x509TrustManager())
      .retryOnConnectionFailure(true)
      .connectionPool(pool())/ / the connection pool
      .connectTimeout(3L, TimeUnit.SECONDS)
      .readTimeout(3L, TimeUnit.SECONDS)
      .build();
Copy the code