前置知识: Java

Java网络编程

00:00
3 min Intermediate 2026/6/14

Socket与HTTP客户端

概述

Java 网络编程涵盖从底层 Socket 到高层 HTTP 客户端的完整体系。Java 11 引入的新 HttpClient API 提供了现代化的 HTTP 客户端,支持同步/异步请求、HTTP/2 和 WebSocket。本文介绍 Java 网络编程的核心 API 和实用技巧。

基础概念

网络编程层次

层次API用途
传输层Socket/ServerSocketTCP/UDP 通信
应用层HttpClientHTTP/HTTPS 请求
应用层WebSocket双向实时通信
网络信息InetAddressIP 地址解析
URL 处理URI/URLURL 解析和构建

核心术语

  • TCP连接的可靠传输协议
  • UDP:无连接的不可靠传输协议
  • HTTP/2支持多路复用、压缩HTTP 协议
  • WebSocket:基于 HTTP 升级的全双工通信协议

快速上手

HttpClient 同步请求

// 创建 HttpClient 实例(推荐复用)
HttpClient client = HttpClient.newHttpClient();

// 构建 GET 请求
HttpRequest request = HttpRequest.newBuilder()
    .uri(URI.create("https://api.example.com/data"))
    .header("Accept", "application/json")
    .GET()
    .build();

// 发送同步请求
HttpResponse<String> response = client.send(request, BodyHandlers.ofString());
System.out.println("状态码: " + response.statusCode());
System.out.println("响应体: " + response.body());

HttpClient 异步请求

// 发送异步请求,返回 CompletableFuture
CompletableFuture<HttpResponse<String>> future =
    client.sendAsync(request, BodyHandlers.ofString());

// 非阻塞处理响应
future.thenAccept(response -> {
    System.out.println("状态码: " + response.statusCode());
    System.out.println("响应体: " + response.body());
}).exceptionally(ex -> {
    System.err.println("请求失败: " + ex.getMessage());
    return null;
});

详细用法

POST 请求与 JSON

// 发送 JSON 格式的 POST 请求
String jsonBody = """
    {
        "name": "张三",
        "age": 25
    }
    """;

HttpRequest postRequest = HttpRequest.newBuilder()
    .uri(URI.create("https://api.example.com/users"))
    .header("Content-Type", "application/json")
    .header("Authorization", "Bearer " + token)
    .POST(BodyPublishers.ofString(jsonBody))
    .build();

HttpResponse<String> response = client.send(postRequest, BodyHandlers.ofString());

超时与重试

// 配置超时和重试
HttpClient client = HttpClient.newBuilder()
    .connectTimeout(Duration.ofSeconds(10))  // 连接超时
    .followRedirects(HttpClient.Redirect.NORMAL) // 跟随重定向
    .build();

HttpRequest request = HttpRequest.newBuilder()
    .uri(URI.create("https://api.example.com/data"))
    .timeout(Duration.ofSeconds(30))  // 请求超时
    .GET()
    .build();

// 简单重试逻辑
int maxRetries = 3;
HttpResponse<String> response = null;
for (int i = 0; i < maxRetries; i++) {
    try {
        response = client.send(request, BodyHandlers.ofString());
        if (response.statusCode() < 500) break; // 非服务端错误,不重试
    } catch (IOException | InterruptedException e) {
        if (i == maxRetries - 1) throw e;
        Thread.sleep(1000 * (i + 1)); // 指数退避
    }
}

文件上传与下载

// 文件上传
Path filePath = Path.of("report.pdf");
HttpRequest uploadRequest = HttpRequest.newBuilder()
    .uri(URI.create("https://api.example.com/upload"))
    .header("Content-Type", "application/octet-stream")
    .POST(BodyPublishers.ofFile(filePath))
    .build();

// 文件下载
HttpRequest downloadRequest = HttpRequest.newBuilder()
    .uri(URI.create("https://example.com/file.zip"))
    .GET()
    .build();

Path outputPath = Path.of("download/file.zip");
HttpResponse<Path> response = client.send(downloadRequest,
    BodyHandlers.ofFile(outputPath));

TCP Socket 编程

// TCP 服务端
try (ServerSocket serverSocket = new ServerSocket(8080)) {
    System.out.println("服务端启动,监听 8080 端口");
    while (true) {
        Socket clientSocket = serverSocket.accept(); // 等待客户端连接
        new Thread(() -> handleClient(clientSocket)).start();
    }
}

// 处理客户端连接
void handleClient(Socket socket) {
    try (socket;
         BufferedReader in = new BufferedReader(
             new InputStreamReader(socket.getInputStream()));
         PrintWriter out = new PrintWriter(socket.getOutputStream(), true)) {
        String line;
        while ((line = in.readLine()) != null) {
            out.println("Echo: " + line); // 回显消息
        }
    } catch (IOException e) {
        e.printStackTrace();
    }
}

// TCP 客户端
try (Socket socket = new Socket("localhost", 8080);
     PrintWriter out = new PrintWriter(socket.getOutputStream(), true);
     BufferedReader in = new BufferedReader(
         new InputStreamReader(socket.getInputStream()))) {
    out.println("Hello, Server!");
    String response = in.readLine();
    System.out.println("服务端响应: " + response);
}

常见场景

REST API 客户端封装

// 封装通用的 REST 客户端
public class RestClient {
    private final HttpClient client;
    private final ObjectMapper mapper = new ObjectMapper();

    public RestClient() {
        this.client = HttpClient.newBuilder()
            .connectTimeout(Duration.ofSeconds(10))
            .build();
    }

    public <T> T get(String url, Class<T> responseType, String token) throws Exception {
        HttpRequest request = HttpRequest.newBuilder()
            .uri(URI.create(url))
            .header("Authorization", "Bearer " + token)
            .GET().build();
        HttpResponse<String> response = client.send(request, BodyHandlers.ofString());
        if (response.statusCode() >= 400) {
            throw new RuntimeException("请求失败: " + response.statusCode());
        }
        return mapper.readValue(response.body(), responseType);
    }

    public <T> T post(String url, Object body, Class<T> responseType) throws Exception {
        String json = mapper.writeValueAsString(body);
        HttpRequest request = HttpRequest.newBuilder()
            .uri(URI.create(url))
            .header("Content-Type", "application/json")
            .POST(BodyPublishers.ofString(json)).build();
        HttpResponse<String> response = client.send(request, BodyHandlers.ofString());
        return mapper.readValue(response.body(), responseType);
    }
}

WebSocket 客户端

// 使用 HttpClient 创建 WebSocket 连接
HttpClient client = HttpClient.newHttpClient();
WebSocket webSocket = client.newWebSocketBuilder()
    .buildAsync(URI.create("wss://echo.example.com/ws"), new WebSocket.Listener() {
        @Override
        public CompletionStage<?> onText(WebSocket ws, CharSequence data, boolean last) {
            System.out.println("收到消息: " + data);
            return null; // 消息处理完成
        }

        @Override
        public CompletionStage<?> onClose(WebSocket ws, int code, String reason) {
            System.out.println("连接关闭: " + reason);
            return null;
        }

        @Override
        public void onError(WebSocket ws, Throwable error) {
            System.err.println("WebSocket 错误: " + error.getMessage());
        }
    }).join();

// 发送消息
webSocket.sendText("Hello, WebSocket!", true);

注意事项

  • HttpClient 实例应复用,不要每次请求都创建新实例
  • 异步请求返回的 CompletableFuture 需要正确处理异常,避免静默失败
  • Socket 编程中务必使用 try-with-resources 确保资源关闭
  • 网络请求设置合理的超时时间,避免无限等待
  • 生产环境应使用连接池管理 HTTP 连接
  • UDP 适合实时要求高但允许的场景,如视频DNS 查询

进阶用法

HTTP/2 多路复用

// HttpClient 默认支持 HTTP/2
HttpClient client = HttpClient.newBuilder()
    .version(HttpClient.Version.HTTP_2) // 优先使用 HTTP/2
    .build();

// HTTP/2 多路复用:多个请求共享一个 TCP 连接
List<CompletableFuture<HttpResponse<String>>> futures = urls.stream()
    .map(url -> client.sendAsync(
        HttpRequest.newBuilder().uri(URI.create(url)).GET().build(),
        BodyHandlers.ofString()))
    .toList();

// 等待所有请求完成
CompletableFuture.allOf(futures.toArray(new CompletableFuture[0])).join();

UDP 数据报

// UDP 发送
try (DatagramSocket socket = new DatagramSocket()) {
    byte[] data = "Hello UDP".getBytes();
    InetAddress address = InetAddress.getByName("localhost");
    DatagramPacket packet = new DatagramPacket(data, data.length, address, 9090);
    socket.send(packet);
}

// UDP 接收
try (DatagramSocket socket = new DatagramSocket(9090)) {
    byte[] buffer = new byte[1024];
    DatagramPacket packet = new DatagramPacket(buffer, buffer.length);
    socket.receive(packet);
    String message = new String(packet.getData(), 0, packet.getLength());
    System.out.println("收到: " + message);
}

知识检测

学习进度

-- 已学文档
--% 知识覆盖率

学习推荐

专注模式