Klien Apache Http mencetak kesalahan I/O [baca]: Waktu baca habis"

Saya menggunakan klien http Apache v4.5 dan menggunakannya sebagai klien REST. Dalam beberapa kasus saya mengenali kesalahan "[baca] kesalahan I/O: Waktu baca habis" yang berasal dari kerangka httpclient ketika membaca konten yang diterima dan menampilkannya sebagai pesan terakhir.

Tampaknya tidak berdampak, namun saya bertanya-tanya apakah ada yang tahu dari mana asalnya dan bagaimana cara mengatasinya. Menurut thread berikut (link) sepertinya menjadi masalah dengan konfigurasi "mutlithreaded".

Namun saya hanya menggunakan konfigurasi default klien http dan ketika saya menggunakan versi v4 saya tidak tahu bagaimana saya dapat mengatur "multithreaded" ke false untuk melihat apakah ada bedanya.

Saya juga mencoba mengatur batas waktu tetapi tidak membantu.

Ada petunjuk?

Catatan:

15:48:05.984 [main] DEBUG org.apache.http.wire - http-outgoing-8 << "HTTP/1.1 200 OK[\r][\n]"
15:48:05.984 [main] DEBUG org.apache.http.wire - http-outgoing-8 << "Date: Tue, 29 Dec 2015 14:48:03 GMT[\r][\n]"
15:48:05.984 [main] DEBUG org.apache.http.wire - http-outgoing-8 << "Server: Apache/2.4.12 (Win32) OpenSSL/1.0.1l PHP/5.6.8[\r][\n]"
15:48:05.984 [main] DEBUG org.apache.http.wire - http-outgoing-8 << "X-Powered-By: PHP/5.6.8[\r][\n]"
15:48:05.985 [main] DEBUG org.apache.http.wire - http-outgoing-8 << "Cache-Control: nocache, private[\r][\n]"
15:48:05.985 [main] DEBUG org.apache.http.wire - http-outgoing-8 << "Content-Length: 99[\r][\n]"
15:48:05.985 [main] DEBUG org.apache.http.wire - http-outgoing-8 << "Keep-Alive: timeout=5, max=99[\r][\n]"
15:48:05.985 [main] DEBUG org.apache.http.wire - http-outgoing-8 << "Connection: Keep-Alive[\r][\n]"
15:48:05.985 [main] DEBUG org.apache.http.wire - http-outgoing-8 << "Content-Type: application/json[\r][\n]"
15:48:05.985 [main] DEBUG org.apache.http.wire - http-outgoing-8 << "[\r][\n]"
15:48:05.985 [main] DEBUG org.apache.http.wire - http-outgoing-8 << "{"success":true,"data":{"id":1946,"location":"http:\/\/localhost:9001\/shop\/api\/articles\/1946"}}"
15:48:06.016 [main] DEBUG org.apache.http.wire - http-outgoing-8 << "[read] I/O error: Read timed out"

inisialisasi klien Http saya

HttpClientBuilder httpBuilder = HttpClientBuilder.create();

//      set timeout did not helped
//      RequestConfig.Builder requestBuilder = RequestConfig.custom();
//      requestBuilder = requestBuilder.setConnectTimeout(timeout);
//      requestBuilder = requestBuilder.setConnectionRequestTimeout(timeout);
//      requestBuilder = requestBuilder.setSocketTimeout(timeout);
//      httpBuilder.setDefaultRequestConfig(requestBuilder.build());

HttpClient httpClient = httpBuilder.build();

person megloff    schedule 29.12.2015    source sumber
comment
Itu tidak mencetak apa pun. Kode Anda mencetaknya. Tidak jelas apa yang Anda tanyakan,   -  person user207421    schedule 04.02.2017
comment
Versi klien http Apache manakah yang Anda gunakan? Saya bertanya apakah ada yang tahu mengapa pesan kesalahan [baca] I/O error: Waktu baca habis muncul.   -  person megloff    schedule 05.02.2017
comment
Saya juga melihat ini. Perlu dicatat juga bahwa tidak ada pengecualian yang dilempar dan tidak dicatat sebagai ERROR, seperti halnya DEBUG.   -  person BrianC    schedule 06.03.2017
comment
Hal ini tampaknya terkait dengan pengumpulan koneksi dengan penggunaan HttpClient multithread, tetapi sebenarnya tidak menimbulkan masalah.   -  person BrianC    schedule 06.03.2017


Jawaban (3)


Saya menggunakan httpclient 4.5.2 dan dalam kasus saya, mengatur batas waktu berdasarkan permintaan membantu:

HttpPost postRequest = new HttpPost("https://...");
postRequest.setHeader(..., ...);

RequestConfig requestConfig = RequestConfig.custom()
                        .setSocketTimeout(1000)
                        .setConnectTimeout(1000)
                        .build();

postRequest.setConfig(requestConfig);
person Ivan Hristov    schedule 09.08.2016

Salah satu alasan terjadinya kesalahan seperti itu mungkin karena server mengikuti kebijakan penutupan koneksi HTTP setelah merespons. Jika demikian halnya, kesalahan ini dapat dihindari dengan menonaktifkan penggunaan kembali koneksi oleh klien, sehingga klien tidak perlu memverifikasi bahwa koneksi masih aktif:

httpBuilder.setConnectionReuseStrategy( (response, context) -> false );
person Sergey Ushakov    schedule 22.06.2017
comment
Anda juga bisa menggunakan org.apache.http.impl.NoConnectionReuseStrategy() baru alih-alih membuat lambda Anda sendiri (walaupun sepele) untuk itu - person Spork; 10.09.2018

Alasannya bukan "multithread", tetapi "http client Pool".

Ini bukan kesalahan, cukup tes soketnya sudah basi, dan ada baiknya bila Anda ingin menggunakan kembali soket. Lihat org/apache/httpcomponents/httpcore/4.4.10/httpcore-4.4.10-sources.jar!/org/Apache/http/pool/AbstractConnPool.java

for (;;) {
    final E leasedEntry = getPoolEntryBlocking(route, state, timeout, tunit, this);
    if (validateAfterInactivity > 0)  {
        if (leasedEntry.getUpdated() + validateAfterInactivity <= System.currentTimeMillis()) {
            if (!validate(leasedEntry)) {
                leasedEntry.close();
                release(leasedEntry, false);
                continue;
            }
        }
    }
    entryRef.set(leasedEntry);
    done.set(true);
    onLease(leasedEntry);
    if (callback != null) {
        callback.completed(leasedEntry);
    }
    return leasedEntry;
}

protected boolean validate(final CPoolEntry entry) {
    return !entry.getConnection().isStale();
}

public boolean isStale() {
    if (!isOpen()) {
        return true;
    }
    try {
        final int bytesRead = fillInputBuffer(1);
        return bytesRead < 0;
    } catch (final SocketTimeoutException ex) {
        return false;
    } catch (final IOException ex) {
        return true;
    }
}

org/apache/httpcomponents/httpcore/4.4.10/httpcore-4.4.10-sources.jar!/org/apache/http/impl/BHttpConnectionBase.java

private int fillInputBuffer(final int timeout) throws IOException {
final Socket socket = this.socketHolder.get();
final int oldtimeout = socket.getSoTimeout();
try {
    socket.setSoTimeout(timeout);
    return this.inbuffer.fillBuffer();
} finally {
    socket.setSoTimeout(oldtimeout);
}
}

Setel batas waktu soket ke 1 ms, dan baca aliran input, kembalikan hasil berikut:

  1. -1 membuat ulang koneksi baru
  2. ">0" menggunakan kembali koneksi
  3. pengecualian batas waktu, gunakan kembali koneksi
  4. Pengecualian IO membuat ulang koneksi baru

Untuk menghindari pesan ini, cukup tetapkan nilai yang tepat untuk validasiAfterInactivity , yaitu nilai minimum waktu habis soket klien, waktu tetap hidup (dikembalikan oleh ConnectionKeepAliveStrategy), waktu tunggu koneksi server habis, dan waktu tunda untuk idleConnectionMonitor. Ini tidak memeriksa status koneksi, jika koneksi direset, koneksi baru akan dibuat.

person avatas    schedule 08.03.2019