杰瑞科技汇

Java HTTP如何设置超时时间?

两种超时

在设置 HTTP 超时时,通常需要区分两种主要的超时类型:

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

    • 含义:客户端与服务器建立 TCP 连接(三次握手)所允许的最长时间。
    • 场景:如果服务器不在线、网络不通或防火墙阻止,连接可能会失败,连接超时可以快速失败,而不是无限等待。
    • 单位:毫秒。
  2. 读取/请求超时

    • 含义:在连接建立成功后,客户端从服务器读取响应(包括响应头和响应体)所允许的最长时间,它也被称为 socketTimeoutrequestTimeout
    • 场景:连接已经建立,但服务器处理请求很慢,或者在数据传输过程中网络变得很慢,读取超时可以防止客户端线程长时间阻塞。
    • 单位:毫秒。

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

HttpURLConnection 是 Java 标准库自带的 HTTP 客户端,从 Java 1.5 开始支持设置超时。

设置方法

通过 setConnectTimeout()setReadTimeout() 方法来设置。

Java HTTP如何设置超时时间?-图2
(图片来源网络,侵删)
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();
            // 1. 设置连接超时时间 (单位: 毫秒)
            // 5秒
            connection.setConnectTimeout(5000);
            // 2. 设置读取超时时间 (单位: 毫秒)
            // 10秒
            connection.setReadTimeout(10000);
            // 设置请求方法
            connection.setRequestMethod("GET");
            // 获取响应码
            int responseCode = connection.getResponseCode();
            System.out.println("Response Code: " + responseCode);
            // 读取响应内容
            if (responseCode == HttpURLConnection.HTTP_OK) { // 200 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("Request timed out!");
            e.printStackTrace();
        } catch (IOException e) {
            System.err.println("An I/O error occurred: " + e.getMessage());
            e.printStackTrace();
        }
    }
}

注意HttpURLConnection 在 Java 9 之后有了一些改进(比如响应体可以更方便地流式读取),但其基本的超时设置方式保持不变。


使用 Apache HttpClient (推荐)

Apache HttpClient 是一个功能强大、灵活且被广泛使用的 HTTP 客户端库,它提供了更精细和强大的超时控制。

Maven 依赖

<dependency>
    <groupId>org.apache.httpcomponents.client5</groupId>
    <artifactId>httpclient5</artifactId>
    <version>5.3.1</version> <!-- 使用最新版本 -->
</dependency>
<dependency>
    <groupId>org.apache.httpcomponents.core5</groupId>
    <artifactId>httpcore5</artifactId>
    <version>5.2</version> <!-- 使用最新版本 -->
</dependency>

设置方法

RequestConfig 中设置超时,然后将这个配置应用到 HttpGetHttpPost 请求上。

import org.apache.hc.client5.http.classic.methods.HttpGet;
import org.apache.hc.client5.http.config.RequestConfig;
import org.apache.hc.client5.http.impl.classic.CloseableHttpClient;
import org.apache.hc.client5.http.impl.classic.CloseableHttpResponse;
import org.apache.hc.client5.http.impl.classic.HttpClients;
import org.apache.hc.core5.http.HttpEntity;
import org.apache.hc.core5.http.io.entity.EntityUtils;
import org.apache.hc.core5.util.Timeout;
public class ApacheHttpClientTimeoutExample {
    public static void main(String[] args) {
        String url = "https://www.example.com";
        // 1. 创建 RequestConfig 对象来配置超时
        RequestConfig requestConfig = RequestConfig.custom()
                // 连接超时: 5秒
                .setConnectTimeout(Timeout.ofMilliseconds(5000))
                // 建立连接后,从服务器获取响应的超时: 10秒
                .setResponseTimeout(Timeout.ofMilliseconds(10000))
                // Socket 超时 (与读取超时类似): 10秒
                .setSocketTimeout(Timeout.ofMilliseconds(10000))
                .build();
        // 2. 创建 HttpClient 实例,并应用 RequestConfig
        try (CloseableHttpClient httpClient = HttpClients.custom()
                .setDefaultRequestConfig(requestConfig)
                .build()) {
            // 3. 创建请求对象
            HttpGet httpGet = new HttpGet(url);
            // 4. 执行请求
            try (CloseableHttpResponse response = httpClient.execute(httpGet)) {
                System.out.println("Response Code: " + response.getCode());
                HttpEntity entity = response.getEntity();
                if (entity != null) {
                    // 将响应体转换为字符串
                    String result = EntityUtils.toString(entity);
                    System.out.println("Response: " + result);
                    // 确保实体内容被完全消耗,以便连接可以重用
                    EntityUtils.consume(entity);
                }
            } catch (org.apache.hc.client5.http.socketTimeoutException e) {
                System.err.println("Request timed out!");
                e.printStackTrace();
            }
        } catch (Exception e) {
            System.err.println("An error occurred: " + e.getMessage());
            e.printStackTrace();
        }
    }
}

说明

Java HTTP如何设置超时时间?-图3
(图片来源网络,侵删)
  • setConnectTimeout: 连接超时。
  • setResponseTimeout: 从连接建立到收到第一个响应字节的总超时时间。
  • setSocketTimeout: 数据传输过程中的超时时间,与 setReadTimeout 类似。

使用 OkHttp (现代流行选择)

OkHttp 是另一个非常流行、高效且易于使用的 HTTP 客户端,特别适合在 Android 和现代 Java 应用中使用。

Maven 依赖

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

设置方法

OkHttpClient.Builder 中设置超时。

import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.Response;
import java.io.IOException;
import java.util.concurrent.TimeUnit;
public class OkHttpTimeoutExample {
    public static void main(String[] args) {
        String url = "https://www.example.com";
        // 1. 创建 OkHttpClient.Builder
        OkHttpClient.Builder builder = new OkHttpClient.Builder();
        // 2. 设置超时时间
        // 连接超时: 5秒
        builder.connectTimeout(5, TimeUnit.SECONDS);
        // 读取超时: 10秒
        builder.readTimeout(10, TimeUnit.SECONDS);
        // 写入超时: 10秒 (适用于 POST 请求)
        builder.writeTimeout(10, TimeUnit.SECONDS);
        // 3. 构建 OkHttpClient
        OkHttpClient client = builder.build();
        // 4. 创建请求
        Request request = new Request.Builder()
                .url(url)
                .build();
        // 5. 执行请求
        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("Request timed out!");
            e.printStackTrace();
        } catch (IOException e) {
            System.err.println("An I/O error occurred: " + e.getMessage());
            e.printStackTrace();
        }
    }
}

说明

  • connectTimeout: 连接超时。
  • readTimeout: 读取响应的超时。
  • writeTimeout: 发送请求体(如 POST 的 JSON 数据)的超时。

总结与对比

特性 java.net.HttpURLConnection Apache HttpClient OkHttp
依赖 JDK 内置,无需额外依赖 需要添加 httpclient5 依赖 需要添加 okhttp 依赖
易用性 较低,API 过时,手动管理资源 中等,需要构建 RequestConfig ,Builder 模式,非常直观
功能 基础功能 强大,高度可定制,支持连接池等 强大,支持 HTTP/2,连接池,WebSocket
超时控制 setConnectTimeout(), setReadTimeout() RequestConfig 中精细设置 OkHttpClient.Builder 中链式调用
推荐场景 简单脚本、不想引入第三方库的项目 企业级应用、需要复杂控制和历史兼容性的项目 现代应用、Android 开发、追求高性能和新特性的项目

最佳实践

  1. 总是设置超时:为了避免你的程序在网络不佳时卡住,为所有生产环境的 HTTP 请求设置合理的超时时间。
  2. 区分两种超时:根据你的应用场景设置不同的连接超时和读取超时,读取超时应该比连接超时更长。
  3. 处理异常:务必捕获 SocketTimeoutException 或其等效异常,并进行适当的处理(如重试、记录日志或向用户提示)。
  4. 选择合适的库
    • 如果项目简单且不想引入依赖,HttpURLConnection 足够用。
    • 如果是大型企业项目或需要非常精细的控制,Apache HttpClient 是一个稳健的选择。
    • 对于新项目,尤其是需要高性能和现代特性的,OkHttp 通常是首选。
分享:
扫描分享到社交APP
上一篇
下一篇