← Backend / Java

25_Java 网络与HTTP客户端

TCP 与 HTTP 边界、JDK HTTP Client、超时、重试和 SSRF 防护。

Java 网络与 HTTP 客户端

学习目标:区分 TCP、HTTP 与应用层契约,并在 Java 服务中安全调用外部 API。

1. 从连接到请求

TCP 提供有序字节流,不自带“一个请求对应一条消息”的业务边界;HTTP 在其上定义方法、路径、头和响应状态。超时至少要考虑连接建立与整个请求处理,重试还要考虑请求是否有副作用。DNS、TLS、代理和连接池都是生产调用链的一部分。

2. JDK HTTP Client 最小示例

import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
import java.time.Duration;

public class Main {
    public static void main(String[] args) throws Exception {
        try (HttpClient client = HttpClient.newBuilder()
                .connectTimeout(Duration.ofSeconds(3)).build()) {
            HttpRequest request = HttpRequest.newBuilder()
                    .uri(URI.create("https://example.com/health"))
                    .timeout(Duration.ofSeconds(5))
                    .GET().build();
            HttpResponse<String> response = client.send(
                    request, HttpResponse.BodyHandlers.ofString());
            System.out.println(response.statusCode());
        }
    }
}

示例中的地址只是占位;运行前改为你控制的测试服务。Java 21 中 HttpClient 可关闭;若项目运行在更早 JDK,需按该版本 API 调整。状态码非 2xx 不一定抛异常,必须显式检查。响应体还需限制大小并验证结构,不能把外部 JSON 直接当可信领域对象。

3. 重试与故障隔离

GET 在满足服务端语义时通常适合有界重试;POST 若已经执行但响应丢失,盲目重试可能创建重复数据。对写入接口先设计幂等键。重试设置最大次数、退避和总时间预算;错误率高时无限重试会放大故障。请求日志记录目标服务、耗时和安全的错误类别,不记录令牌或完整敏感响应。

4. 安全边界与实验

如果 URL 来自用户输入,直接请求可能造成 SSRF,让服务访问内网或云元数据地址。使用服务端允许列表、受控 DNS/网络策略与重定向规则,不要只检查字符串前缀。

练习:调用本机测试服务分别模拟 200、500、慢响应与连接失败,记录每种结果的超时和重试决策。