HttpURLConnection超时设置


123

如果要用5秒钟以上的时间来连接URL,我想返回false-使用Java怎么可能?这是我用来检查URL是否有效的代码

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

Answers:


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 2013年

2
@ spaaarky21是正确的。但是,如果正在构建UI,并且想通知用户发生了超时,则必须在IOException之前捕获SocketTimeoutException,否则,将无法访问。
Clocker

3
注意!您需要setConnectTimeout在任何隐式连接的方法之前调用(基本上,如果已连接,则抛出IllegalStateException的所有方法)。理想情况下,将setConnectTimeout(readTimeout)设为第一个调用的方法。
亚当·根特

4
它对我不起作用。但是,添加后con.setReadTimeout(),它按预期工作。
Paulo

115

您可以这样设置超时时间,

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

2
我们可以指定的最大超时值是多少?
Pacerier

7
@Pacerier文档未明确说明。如果值是负数,则确实会抛出IllegalArgumentException(值0表示无限期等待)。由于超时是一个无符号的32位int,因此我猜最大超时约为49天(尽管我严重怀疑此值对任何人都有用)。
杰伊·西德里

1

如果HTTP连接没有超时,则可以在后台线程本身(AsyncTask,Service等)中实现超时检查器,以下类是Customize 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

这里的要点是取消doInBackground()中间的AsyncTask,而这需要花费太多时间来执行,而不是onPreExecute(),我也想取消仅此AsyncTask实例,这需要太多时间并保留其他实例,非常感谢您的反馈。
Ayman Mahgoub

2
我认为我的信息不够清楚。我不是说您应该在onPreExecute()中取消,而是说您应该在onPreExecute()中创建处理程序,并从主线程中发布延迟的取消。这样,您将使用主线程作为循环程序线程,并且您当然可以稍后在doInBackground()执行时取消AsyncTask,因为主线程也与后台线程同时运行。
BladeCoder

-1

我可以通过添加简单的行来获得针对此类类似问题的解决方案

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

我的要求是知道响应代码,为此,仅获取元信息就足够了,而不是获取完整的响应正文。

默认的请求方法是GET,这要花很多时间才能返回,最终使我抛出SocketTimeoutException。当我将Request Method设置为HEAD时,响应速度非常快。


1
这绝不是解决方案,您正在将request方法更改为HEAD不会产生任何响应主体的请求。
Sveinung Kval Bakken

这不会为原始问题添加任何内容。OP .setRequestMethod("HEAD")在他们的代码中。奇怪的是,此描述正是我减少“打开的文件过多”问题所需要的。那谢谢啦?
约书亚·品特
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.