Настройки тайм-аута HttpURLConnection


123

Я хочу вернуть false, если для подключения 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. Если оба блока catch делают одно и то же, вы можете просто поймать IOException.
— spaaarky21 05

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-битное целое число без знака, я предполагаю, что максимальный тайм-аут будет около 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;
    };
 }

Совершенно необязательно создавать новый поток петлителя только для того, чтобы запланировать вызов функции cancel (). Вы можете сделать это из основного потока в onPreExecute(). Кроме того, если вы отмените задачу вручную, вы также должны отменить запланированный вызов, чтобы избежать утечек.
— BladeCoder

Дело здесь в том, чтобы отменить AsyncTask в середине doInBackground (), когда выполнение занимает слишком много времени, а не в onPreExecute (), также я хочу отменить только этот экземпляр AsyncTask, который занимает слишком много времени, и оставить остальных, очень признателен ваш отзыв.
— Ayman Mahgoub

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.