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

(图片来源网络,侵删)
-
连接超时
- 含义:客户端与服务器建立 TCP 连接(三次握手)所花费的最长时间。
- 场景:如果目标服务器 IP 不可达、网络延迟过高或防火墙阻拦,连接可能会失败,设置连接超时可以快速失败,而不是无限等待。
- 单位:毫秒。
-
读取超时
- 含义:客户端成功建立连接后,从服务器读取数据(接收响应头或响应体)所花费的最长时间。
- 场景:服务器已经建立连接,但由于处理请求慢、数据库查询慢或网络传输慢,迟迟不返回数据,设置读取超时可以避免客户端线程长时间阻塞。
- 单位:毫秒。
使用 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 对象来实现的。

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

(图片来源网络,侵删)
