Налаштування часу очікування з'єднання HttpURLC


123

Я хочу повернути помилкове значення, якщо URL-адресі потрібно більше 5 секунд для підключення - як це можливо за допомогою Java? Ось код, який я використовую, щоб перевірити, чи дійсна URL-адреса

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

Відповіді:


201

HttpURLConnectionмає метод setConnectTimeout .

Просто встановіть час очікування на 5000 мілісекунд, а потім зафіксуйте java.net.SocketTimeoutException

Ваш код повинен виглядати приблизно так:


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;
}



3
Я встановлюю значення на 10 хвилин. Однак це кидає мені java.net.ConnectException: Connection timed out: connectще 2 хвилини. Чи знаєте ви, що викликає проблему?
Pacerier

5
SocketTimeoutException - це підклас IOException. Якщо обидва блоки захоплення роблять те саме, ви можете просто зловити IOException.
spaaarky21

2
@ spaaarky21 є правильним. Якщо ви створюєте інтерфейс користувача і хочете повідомити своїх користувачів про те, що настав час очікування, ви повинні вловити SocketTimeoutException перед IOException, якщо ні, це буде недоступно.
Clocker

3
NB! вам потрібно зателефонувати setConnectTimeoutперед будь-яким із методів, які неявно підключаються (в основному всі методи, які викидають IllegalStateException, якщо вони вже підключені). В ідеалі зробити setConnectTimeout (readTimeout) першими названими методами.
Адам Гент

4
Це не працювало для мене. Але, додавши con.setReadTimeout(), це працювало як очікувалося.
Пауло

115

Ви можете встановити такий час очікування,

con.setConnectTimeout(connectTimeout);
con.setReadTimeout(socketTimeout);

2
Яке максимальне значення таймауту ми можемо вказати?
Pacerier

7
@Pacerier Документи не заявляють це прямо. Це закидає IllegalArgumentException, якщо значення негативне (значення 0 означатиме чекати нескінченно). Оскільки тайм-аут - це непідписаний 32-бітний int, я б припустив, що максимальний час очікування складе близько 49 днів (хоча я серйозно сумніваюся, що таке значення буде корисним для будь-кого).
Джей Сидрі

1

Якщо HTTP-з’єднання не закінчиться, ви можете реалізувати перевірку тайм-аута у самій фоновій нитці (AsyncTask, Service тощо), наступний клас є прикладом для налаштування AsyncTask, який очікує час після певного періоду

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);
}

Зразок для цього

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;
    };
 }

Абсолютно непотрібно створювати новий потік петлі просто для планування виклику для скасування (). Це можна зробити з головної нитки в onPreExecute(). Крім того, якщо ви скасуєте завдання вручну, вам слід також скасувати запланований дзвінок, щоб уникнути витоків.
BladeCoder

Тут важливо скасувати AsyncTask посеред doInBackground (), коли на виконання потрібно не занадто багато часу, а не на onPreExecute (), також я хочу скасувати лише цей екземпляр AsyncTask, який займає занадто багато часу, і тримати інших, дуже вдячний ваш відгук.
Айман Махгуб

2
Я думаю, що моє повідомлення було недостатньо зрозумілим. Я не сказав, що ви повинні скасувати в onPreExecute (), я сказав, що вам слід створити обробник в onPreExecute () і опублікувати відкладене скасування з основного потоку. Таким чином, ви будете використовувати головний потік як петлю петлі, і, звичайно, можете скасувати AsyncTask пізніше, поки doInBackground () виконує, оскільки головний потік також працює одночасно з фоновим потоком.
BladeCoder

-1

Я міг би знайти рішення для подібної проблеми з додаванням простої лінії

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

Моя вимога полягала в тому, щоб знати код відповіді, і для цього достатньо було лише отримати метаінформацію, а не отримати повний орган відповіді.

Метод запиту за замовчуванням GET, і це потребувало багато часу, щоб повернутися, нарешті, кинувши мені SocketTimeoutException. Відповідь була досить швидкою, коли я встановив метод запиту HEAD.


1
Це жодним чином не рішення, ви змінюєте метод запиту на HEADзапит, який не видасть жодного органу відповіді.
Sveinung Kval Bakken

Це не додає нічого до початкового питання. ОП має .setRequestMethod("HEAD")у своєму коді. Як не дивно, саме цей опис був саме тим, що мені потрібно було скоротити випуск "Забагато відкритих файлів". Тож спасибі?
Джошуа Пінтер
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.