杰瑞科技汇

Java如何设置HTTP请求超时时间?

两种超时

在设置 HTTP 超时时,我们通常需要区分两种超时:

Java如何设置HTTP请求超时时间?-图1
(图片来源网络,侵删)
  1. 连接超时

    • 含义:客户端与服务器建立 TCP 连接(三次握手)所花费的最长时间。
    • 场景:如果目标服务器 IP 不可达、网络延迟过高或防火墙阻拦,连接可能会失败,设置连接超时可以快速失败,而不是无限等待。
    • 单位:毫秒。
  2. 读取超时

    • 含义:客户端成功建立连接后,从服务器读取数据(接收响应头或响应体)所花费的最长时间。
    • 场景:服务器已经建立连接,但由于处理请求慢、数据库查询慢或网络传输慢,迟迟不返回数据,设置读取超时可以避免客户端线程长时间阻塞。
    • 单位:毫秒。

使用 java.net.HttpURLConnection (JDK 内置)

HttpURLConnection 是 Java 标准库的一部分,无需额外依赖,从 Java 1.5 开始,它支持设置连接和读取超时。

示例代码

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.URL;
public class HttpURLConnectionTimeoutExample {
    public static void main(String[] args) {
        String urlString = "https://www.example.com"; // 替换成你要请求的URL
        try {
            URL url = new URL(urlString);
            HttpURLConnection connection = (HttpURLConnection) url.openConnection();
            // --- 设置超时时间 (核心部分) ---
            // 连接超时: 5秒
            connection.setConnectTimeout(5000);
            // 读取超时: 10秒
            connection.setReadTimeout(10000);
            // 设置请求方法 (GET, POST等)
            connection.setRequestMethod("GET");
            // 获取响应码
            int responseCode = connection.getResponseCode();
            System.out.println("Response Code: " + responseCode);
            // 如果请求成功,读取响应内容
            if (responseCode == HttpURLConnection.HTTP_OK) {
                BufferedReader in = new BufferedReader(
                        new InputStreamReader(connection.getInputStream()));
                String inputLine;
                StringBuilder response = new StringBuilder();
                while ((inputLine = in.readLine()) != null) {
                    response.append(inputLine);
                }
                in.close();
                System.out.println("Response: " + response.toString());
            } else {
                System.out.println("GET request failed");
            }
        } catch (java.net.SocketTimeoutException e) {
            // 捕获超时异常
            System.err.println("请求超时: " + e.getMessage());
            // 可以在这里进行重试逻辑或其他处理
        } catch (IOException e) {
            System.err.println("发生IO异常: " + e.getMessage());
        }
    }
}

代码解释

  • connection.setConnectTimeout(5000);:设置连接超时为 5000 毫秒(5秒)。
  • connection.setReadTimeout(10000);:设置读取超时为 10000 毫秒(10秒)。
  • java.net.SocketTimeoutException:当发生超时时,HttpURLConnection 会抛出这个异常,你需要用 try-catch 块来捕获它,以便进行相应的错误处理。

使用 Apache HttpClient (功能更强大)

Apache HttpClient 是一个功能更全面、更灵活的 HTTP 客户端库,是企业级应用中的首选,它的超时设置方式与 HttpURLConnection 不同,是通过构建 RequestConfig 对象来实现的。

Java如何设置HTTP请求超时时间?-图2
(图片来源网络,侵删)

Maven 依赖

<dependency>
    <groupId>org.apache.httpcomponents</groupId>
    <artifactId>httpclient</artifactId>
    <version>4.5.14</version> <!-- 使用较新版本 -->
</dependency>

示例代码

import org.apache.http.HttpResponse;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.util.EntityUtils;
public class ApacheHttpClientTimeoutExample {
    public static void main(String[] args) {
        String urlString = "https://www.example.com";
        // --- 创建RequestConfig来设置超时 ---
        RequestConfig requestConfig = RequestConfig.custom()
                // 连接超时: 5秒
                .setConnectTimeout(5000)
                //socket超时 (等同于读取超时): 10秒
                .setSocketTimeout(10000)
                // 从连接池获取连接的超时时间
                .setConnectionRequestTimeout(2000) 
                .build();
        // 使用RequestConfig创建HttpClient
        try (CloseableHttpClient httpClient = HttpClients.custom()
                .setDefaultRequestConfig(requestConfig)
                .build()) {
            HttpGet request = new HttpGet(urlString);
            System.out.println("Executing request: " + request.getRequestLine());
            HttpResponse response = httpClient.execute(request);
            System.out.println("Response Code: " + response.getStatusLine().getStatusCode());
            // 读取响应实体
            String responseBody = EntityUtils.toString(response.getEntity());
            System.out.println("Response: " + responseBody);
        } catch (org.apache.http.conn.ConnectTimeoutException e) {
            // 连接超时
            System.err.println("连接超时: " + e.getMessage());
        } catch (java.net.SocketTimeoutException e) {
            // 读取超时
            System.err.println("读取超时: " + e.getMessage());
        } catch (Exception e) {
            System.err.println("发生异常: " + e.getMessage());
        }
    }
}

代码解释

  • RequestConfig:这是一个配置类,用于设置所有与请求相关的参数,包括超时。
  • setConnectTimeout(5000):连接超时。
  • setSocketTimeout(10000):Socket 超时,这对应于 HttpURLConnection 的读取超时,指的是从服务器获取数据(包括响应头和响应体)的超时时间。
  • setConnectionRequestTimeout(2000):这是一个额外的超时,表示从连接池中获取一个可用连接的超时时间,如果你使用了连接池,这个设置很重要。
  • org.apache.http.conn.ConnectTimeoutExceptionjava.net.SocketTimeoutException:Apache HttpClient 会根据超时的类型抛出不同的异常,方便你进行精确的捕获和处理。

使用 OkHttp (现代、高效)

OkHttp 是目前 Android 开发和许多 Java 后端项目中的流行选择,以其高效和简洁的 API 而闻名。

Maven 依赖

<dependency>
    <groupId>com.squareup.okhttp3</groupId>
    <artifactId>okhttp</artifactId>
    <version>4.12.0</version> <!-- 使用较新版本 -->
</dependency>

示例代码

import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.Response;
import java.io.IOException;
public class OkHttpTimeoutExample {
    public static void main(String[] args) {
        String urlString = "https://www.example.com";
        // --- 创建OkHttpClient并设置超时 ---
        OkHttpClient client = new OkHttpClient.Builder()
                // 连接超时: 5秒
                .connectTimeout(5, java.util.concurrent.TimeUnit.SECONDS)
                // 读取超时: 10秒
                .readTimeout(10, java.util.concurrent.TimeUnit.SECONDS)
                // 写入超时 (POST/PUT请求): 10秒
                .writeTimeout(10, java.util.concurrent.TimeUnit.SECONDS)
                .build();
        Request request = new Request.Builder()
                .url(urlString)
                .build();
        try (Response response = client.newCall(request).execute()) {
            if (!response.isSuccessful()) {
                throw new IOException("Unexpected code " + response);
            }
            // 获取响应体
            System.out.println("Response Code: " + response.code());
            System.out.println("Response Body: " + response.body().string());
        } catch (java.net.SocketTimeoutException e) {
            // 连接或读取超时
            System.err.println("请求超时: " + e.getMessage());
        } catch (IOException e) {
            System.err.println("发生IO异常: " + e.getMessage());
        }
    }
}

代码解释

  • OkHttpClient.Builder:OkHttp 使用建造者模式来配置客户端。
  • connectTimeout(5, TimeUnit.SECONDS):设置连接超时,时间单位需要明确指定(如 SECONDS, MILLISECONDS)。
  • readTimeout(10, TimeUnit.SECONDS):设置读取超时。
  • writeTimeout(10, TimeUnit.SECONDS):设置写入超时,这在发送大请求体(如文件上传)时非常有用。
  • java.net.SocketTimeoutException:当发生超时时,OkHttp 会抛出这个异常。

总结与对比

特性 java.net.HttpURLConnection Apache HttpClient OkHttp
依赖 JDK 内置,无需引入 需要引入 httpclient 需要引入 okhttp
易用性 简单,API 较为基础 功能强大,但 API 相对复杂 API 现代且非常简洁
超时设置 setConnectTimeout(), setReadTimeout() RequestConfig 对象 OkHttpClient.Builder 链式调用
连接池 无内置支持 有,功能强大 有,且性能优异
适用场景 简单脚本、小型应用、不想引入第三方库 企业级应用、需要高度定制和灵活性的场景 Android 开发、现代 Java 应用、追求高性能

最佳实践建议

  1. 永远设置超时:在任何生产环境的网络请求中,都应该设置合理的连接超时和读取超时,以避免线程被无限期阻塞。
  2. 根据场景调整:根据你的应用场景和网络环境调整超时时间,调用内部服务的超时可以设置得短一些(如2-5秒),而调用外部第三方 API 的超时可以设置得长一些(如10-30秒)。
  3. 处理超时异常:务必捕获 SocketTimeoutException 或特定库的超时异常,并实现重试机制或向用户友好的错误提示。
  4. 选择合适的库
    • 如果只是简单用一下,HttpURLConnection 足够。
    • 如果是复杂的企业级 Java 项目,Apache HttpClient 是一个非常成熟和可靠的选择。
    • 如果是新项目,特别是可能涉及 Android 或追求更现代 API,OkHttp 是一个非常优秀的选择。
Java如何设置HTTP请求超时时间?-图3
(图片来源网络,侵删)
分享:
扫描分享到社交APP
上一篇
下一篇