HttpURLConnection 超时设置

Posted

技术标签:

【中文标题】HttpURLConnection 超时设置【英文标题】:HttpURLConnection timeout settings 【发布时间】:2011-02-17 12:01:32 【问题描述】:

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

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

【问题讨论】:

【参考方案1】:

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;

【讨论】:

我将值设置为 10 分钟。然而,它甚至在 2 分钟结束之前给我一个java.net.ConnectException: Connection timed out: connect。你知道是什么导致了这个问题吗? SocketTimeoutException 是 IOException 的子类。如果两个 catch 块做同样的事情,你可以只捕获 IOException。 @spaarky21 是正确的。但是,如果您正在构建 UI 并且想要通知用户发生超时,则必须在 IOException 之前捕获 SocketTimeoutException,否则将无法访问。 注意!!! 您需要在任何隐式连接的方法之前调用setConnectTimeout(基本上是所有已连接时抛出 IllegalStateException 的方法)。理想情况下,首先调用 setConnectTimeout (readTimeout) 方法。 它对我不起作用。但是,添加con.setReadTimeout() 后,它按预期工作。【参考方案2】:

你可以这样设置超时,

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

【讨论】:

我们可以指定的最大超时时间是多少? @Pacerier 文档没有明确说明这一点。如果值为负数(值为 0 表示无限期等待),它会抛出 IllegalArgumentException。由于超时是一个无符号的 32 位整数,我猜最大超时大约是 49 天(尽管我严重怀疑这个值对任何人都有帮助)。 我同时使用了超时,但仍然出现超时错误。但是当我检查日志时,我的请求需要 20 秒,但我给了 100 秒的 setConnectTimeout【参考方案3】:

如果 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()的调用而创建一个新的looper线程。您可以从onPreExecute() 中的主线程执行此操作。另外,如果您手动取消任务,您还应该取消预定的调用以避免泄漏。 这里的要点是在 doInBackground() 中间取消 AsyncTask,因为它在执行而不是在 onPreExecute() 上花费了太多时间,我也想只取消这个 AsyncTask 的实例,这需要太多时间时间并保留其他人,非常感谢您的反馈。 我认为我的信息不够清楚。我没有说你应该在 onPreExecute() 中取消,我说你应该在 onPreExecute() 中创建处理程序并从主线程发布延迟取消。这样你就可以使用主线程作为 looper 线程,当然你可以在 doInBackground() 执行时取消 AsyncTask,因为主线程也和后台线程同时运行。【参考方案4】:

我可以通过添加一条简单的线来解决此类类似问题

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

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

默认的请求方法是 GET,这需要很长时间才能返回,最后抛出了 SocketTimeoutException。当我将请求方法设置为 HEAD 时,响应非常快。

【讨论】:

这绝不是解决方案,您将请求方法更改为 HEAD 请求,它不会产生任何响应正文。 这不会对原始问题添加任何内容。 OP 在他们的代码中有.setRequestMethod("HEAD")。奇怪的是,这个描述正是我减少“打开的文件太多”问题所需要的。那么谢谢?

以上是关于HttpURLConnection 超时设置的主要内容,如果未能解决你的问题,请参考以下文章

关于spring resttemplate超时设置

HttpURLConnection.connect 卡死 死锁怎么解决

一定要为HttpUrlConnection设置connectTimeout属性以防止连接被阻塞

Android之HttpURLConnection

HttpURLConnection getInputStream:总是在 180 秒后超时

Android HttpUrlConnection如何在请求头中设置cookie?