Pengaturan batas waktu HttpURLConnection

123

Saya ingin mengembalikan false jika URL membutuhkan lebih dari 5 detik untuk terhubung - bagaimana ini mungkin menggunakan Java? Berikut adalah kode yang saya gunakan untuk memeriksa apakah URL tersebut valid

HttpURLConnection.setFollowRedirects(false);
HttpURLConnection con = (HttpURLConnection) new URL(url).openConnection();
con.setRequestMethod("HEAD");
return (con.getResponseCode() == HttpURLConnection.HTTP_OK);
Maleakhi
sumber

Jawaban:

201

HttpURLConnectionmemiliki metode setConnectTimeout .

Cukup setel batas waktu ke 5000 milidetik, lalu tangkap java.net.SocketTimeoutException

Kode Anda akan terlihat seperti ini:


try {
   HttpURLConnection.setFollowRedirects(false);
   HttpURLConnection con = (HttpURLConnection) new URL(url).openConnection();
   con.setRequestMethod("HEAD");

   con.setConnectTimeout(5000); //set timeout to 5 seconds

   return (con.getResponseCode() == HttpURLConnection.HTTP_OK);
} catch (java.net.SocketTimeoutException e) {
   return false;
} catch (java.io.IOException e) {
   return false;
}


dbyrne
sumber
3
Saya mengatur nilainya menjadi 10 menit. Namun itu melempar saya java.net.ConnectException: Connection timed out: connectbahkan sebelum 2 menit habis. Tahukah Anda apa yang menyebabkan masalah?
Pacerier
5
SocketTimeoutException adalah subclass dari IOException. Jika kedua blok penangkap melakukan hal yang sama, Anda bisa menangkap IOException.
spaaarky21
2
@ spaaarky21 benar. Namun, jika Anda membuat UI dan ingin memberi tahu pengguna bahwa waktu tunggu telah terjadi, Anda harus menangkap SocketTimeoutException sebelum IOException, jika tidak, waktu tunggu tidak akan dapat dijangkau.
Clocker
3
NB !!! Anda perlu memanggil setConnectTimeoutsebelum salah satu metode yang terhubung secara implisit (pada dasarnya semua metode yang menampilkan IllegalStateException jika sudah terhubung). Idealnya, jadikan setConnectTimeout (readTimeout) sebagai metode pertama yang dipanggil.
Adam Gent
4
Itu tidak berhasil untuk saya. Tapi, setelah ditambahkan con.setReadTimeout(), itu berfungsi seperti yang diharapkan.
Paulo
115

Anda dapat mengatur waktu tunggu seperti ini,

con.setConnectTimeout(connectTimeout);
con.setReadTimeout(socketTimeout);
ZZ Coder
sumber
2
Berapa nilai maksimum batas waktu yang dapat kita tentukan?
Pacerier
7
@Pacerier Dokumen tidak menyatakan ini secara eksplisit. Itu memunculkan IllegalArgumentException jika nilainya negatif (nilai 0 berarti menunggu tanpa batas). Karena batas waktu adalah 32bit int unsigned, saya kira batas waktu maksimum adalah sekitar 49 hari (meskipun saya benar-benar meragukan ini nilai seperti itu akan membantu siapa pun).
Jay Sidri
1

Jika Koneksi HTTP tidak kehabisan waktu, Anda dapat mengimplementasikan pemeriksa waktu tunggu di utas latar belakang itu sendiri (AsyncTask, Layanan, dll), kelas berikut adalah contoh untuk Sesuaikan AsyncTask yang waktu tunggu habis setelah periode tertentu

public abstract class AsyncTaskWithTimer<Params, Progress, Result> extends
    AsyncTask<Params, Progress, Result> {

private static final int HTTP_REQUEST_TIMEOUT = 30000;

@Override
protected Result doInBackground(Params... params) {
    createTimeoutListener();
    return doInBackgroundImpl(params);
}

private void createTimeoutListener() {
    Thread timeout = new Thread() {
        public void run() {
            Looper.prepare();

            final Handler handler = new Handler();
            handler.postDelayed(new Runnable() {
                @Override
                public void run() {

                    if (AsyncTaskWithTimer.this != null
                            && AsyncTaskWithTimer.this.getStatus() != Status.FINISHED)
                        AsyncTaskWithTimer.this.cancel(true);
                    handler.removeCallbacks(this);
                    Looper.myLooper().quit();
                }
            }, HTTP_REQUEST_TIMEOUT);

            Looper.loop();
        }
    };
    timeout.start();
}

abstract protected Result doInBackgroundImpl(Params... params);
}

Contoh untuk ini

public class AsyncTaskWithTimerSample extends AsyncTaskWithTimer<Void, Void, Void> {

    @Override
    protected void onCancelled(Void void) {
        Log.d(TAG, "Async Task onCancelled With Result");
        super.onCancelled(result);
    }

    @Override
    protected void onCancelled() {
        Log.d(TAG, "Async Task onCancelled");
        super.onCancelled();
    }

    @Override
    protected Void doInBackgroundImpl(Void... params) {
        // Do background work
        return null;
    };
 }
Ayman Mahgoub
sumber
Anda sama sekali tidak perlu membuat utas looper baru hanya untuk menjadwalkan panggilan ke cancel (). Anda dapat melakukannya dari utas utama di onPreExecute(). Selain itu, jika Anda membatalkan tugas secara manual, Anda juga harus membatalkan panggilan terjadwal untuk menghindari kebocoran.
BladeCoder
Maksudnya di sini adalah untuk membatalkan AsyncTask di tengah doInBackground () ketika dibutuhkan terlalu banyak waktu saat eksekusi tidak di onPreExecute (), juga saya ingin membatalkan hanya contoh AsyncTask ini yang membutuhkan terlalu banyak waktu dan menjaga yang lain, sangat menghargai tanggapan Anda.
Ayman Mahgoub
2
Saya pikir pesan saya tidak cukup jelas. Saya tidak mengatakan Anda harus membatalkan di onPreExecute (), saya mengatakan Anda harus membuat Handler di onPreExecute () dan memposting pembatalan tertunda dari utas utama. Dengan cara ini Anda akan menggunakan utas utama sebagai utas looper dan tentu saja Anda bisa membatalkan AsyncTask nanti saat doInBackground () dijalankan karena utas utama juga berjalan bersamaan dengan utas latar belakang.
BladeCoder
-1

Saya bisa mendapatkan solusi untuk masalah serupa dengan penambahan garis sederhana

HttpURLConnection hConn = (HttpURLConnection) url.openConnection();
hConn.setRequestMethod("HEAD");

Persyaratan saya adalah mengetahui kode respons dan untuk itu hanya mendapatkan informasi meta saja sudah cukup, alih-alih mendapatkan isi respons lengkap.

Metode permintaan default adalah GET dan membutuhkan banyak waktu untuk kembali, akhirnya melemparkan saya SocketTimeoutException. Responnya cukup cepat ketika saya mengatur Metode Permintaan ke HEAD.

Subrata Nath
sumber
1
Ini bukanlah solusi apa pun, Anda mengubah metode HEADpermintaan menjadi permintaan yang tidak akan menghasilkan isi respons apa pun.
Sveinung Kval Bakken
Ini tidak menambahkan apapun pada pertanyaan awal. OP ada .setRequestMethod("HEAD")di kodenya. Anehnya, penjelasan ini persis seperti yang saya butuhkan untuk mengurangi masalah "Terlalu banyak file yang terbuka". Jadi terima kasih?
Joshua Pinter