Skip to content

HttpServer

文件信息

  • 📄 原文件:HttpServer.java
  • 🔤 语言:java

简单 HTTP 服务器 使用 Java 内置的 HttpServer 实现简单的 REST API。 功能:

完整代码

java
import com.sun.net.httpserver.*;
import java.io.*;
import java.net.*;
import java.nio.charset.*;
import java.util.*;
import java.util.concurrent.*;
import java.time.*;
import java.time.format.*;

/**
 * ============================================================
 *                    简单 HTTP 服务器
 * ============================================================
 * 使用 Java 内置的 HttpServer 实现简单的 REST API。
 *
 * 功能:
 * - 基本路由
 * - JSON 响应
 * - 请求日志
 * - 错误处理
 *
 * 运行后访问:
 * - http://localhost:8080/         首页
 * - http://localhost:8080/api/time 当前时间
 * - http://localhost:8080/api/echo 回显请求
 * - http://localhost:8080/api/users 用户列表
 * ============================================================
 */
public class HttpServer {

    private static final int PORT = 8080;
    private static final DateTimeFormatter FORMATTER =
        DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");

    // 模拟数据库
    private static final List<User> users = new CopyOnWriteArrayList<>(List.of(
        new User(1, "Alice", "[email protected]"),
        new User(2, "Bob", "[email protected]"),
        new User(3, "Charlie", "[email protected]")
    ));

    public static void main(String[] args) throws IOException {
        com.sun.net.httpserver.HttpServer server =
            com.sun.net.httpserver.HttpServer.create(new InetSocketAddress(PORT), 0);

        // 配置路由
        server.createContext("/", HttpServer::handleHome);
        server.createContext("/api/time", HttpServer::handleTime);
        server.createContext("/api/echo", HttpServer::handleEcho);
        server.createContext("/api/users", HttpServer::handleUsers);

        // 使用虚拟线程(Java 21+)
        server.setExecutor(Executors.newVirtualThreadPerTaskExecutor());

        server.start();
        System.out.println("服务器启动在 http://localhost:" + PORT);
        System.out.println("\n可用端点:");
        System.out.println("  GET  /           - 首页");
        System.out.println("  GET  /api/time   - 当前时间");
        System.out.println("  POST /api/echo   - 回显请求体");
        System.out.println("  GET  /api/users  - 获取用户列表");
        System.out.println("  POST /api/users  - 创建用户");
        System.out.println("\n按 Ctrl+C 停止服务器");
    }

    /**
     * 首页处理
     */
    private static void handleHome(HttpExchange exchange) throws IOException {
        logRequest(exchange);

        String html = """
            <!DOCTYPE html>
            <html>
            <head>
                <title>Java HTTP Server</title>
                <style>
                    body { font-family: Arial, sans-serif; max-width: 800px; margin: 50px auto; padding: 20px; }
                    h1 { color: #333; }
                    .endpoint { background: #f5f5f5; padding: 10px; margin: 10px 0; border-radius: 5px; }
                    code { background: #e0e0e0; padding: 2px 6px; border-radius: 3px; }
                </style>
            </head>
            <body>
                <h1>Java HTTP Server</h1>
                <p>欢迎使用 Java 内置 HTTP 服务器!</p>

                <h2>可用端点</h2>
                <div class="endpoint">
                    <code>GET /api/time</code> - 获取当前时间
                </div>
                <div class="endpoint">
                    <code>POST /api/echo</code> - 回显请求体
                </div>
                <div class="endpoint">
                    <code>GET /api/users</code> - 获取用户列表
                </div>
                <div class="endpoint">
                    <code>POST /api/users</code> - 创建用户
                </div>

                <h2>示例</h2>
                <pre>
curl http://localhost:8080/api/time
curl -X POST -d "Hello" http://localhost:8080/api/echo
curl http://localhost:8080/api/users
                </pre>
            </body>
            </html>
            """;

        sendResponse(exchange, 200, "text/html", html);
    }

    /**
     * 时间 API
     */
    private static void handleTime(HttpExchange exchange) throws IOException {
        logRequest(exchange);

        if (!exchange.getRequestMethod().equals("GET")) {
            sendError(exchange, 405, "Method Not Allowed");
            return;
        }

        String json = """
            {
                "timestamp": "%s",
                "unix": %d,
                "timezone": "%s"
            }
            """.formatted(
                LocalDateTime.now().format(FORMATTER),
                System.currentTimeMillis() / 1000,
                ZoneId.systemDefault().getId()
            );

        sendResponse(exchange, 200, "application/json", json);
    }

    /**
     * Echo API
     */
    private static void handleEcho(HttpExchange exchange) throws IOException {
        logRequest(exchange);

        if (!exchange.getRequestMethod().equals("POST")) {
            sendError(exchange, 405, "Method Not Allowed");
            return;
        }

        String body = new String(exchange.getRequestBody().readAllBytes(), StandardCharsets.UTF_8);
        String contentType = exchange.getRequestHeaders().getFirst("Content-Type");

        String json = """
            {
                "method": "%s",
                "path": "%s",
                "contentType": "%s",
                "contentLength": %d,
                "body": "%s",
                "headers": %s
            }
            """.formatted(
                exchange.getRequestMethod(),
                exchange.getRequestURI().getPath(),
                contentType != null ? contentType : "none",
                body.length(),
                escapeJson(body),
                headersToJson(exchange.getRequestHeaders())
            );

        sendResponse(exchange, 200, "application/json", json);
    }

    /**
     * 用户 API
     */
    private static void handleUsers(HttpExchange exchange) throws IOException {
        logRequest(exchange);

        String method = exchange.getRequestMethod();

        switch (method) {
            case "GET" -> handleGetUsers(exchange);
            case "POST" -> handleCreateUser(exchange);
            default -> sendError(exchange, 405, "Method Not Allowed");
        }
    }

    private static void handleGetUsers(HttpExchange exchange) throws IOException {
        // 解析查询参数
        String query = exchange.getRequestURI().getQuery();
        Map<String, String> params = parseQuery(query);

        List<User> result = users;

        // 简单过滤
        if (params.containsKey("name")) {
            String name = params.get("name");
            result = users.stream()
                .filter(u -> u.name().toLowerCase().contains(name.toLowerCase()))
                .toList();
        }

        StringBuilder json = new StringBuilder("[\n");
        for (int i = 0; i < result.size(); i++) {
            User u = result.get(i);
            json.append("""
                    {
                        "id": %d,
                        "name": "%s",
                        "email": "%s"
                    }""".formatted(u.id(), u.name(), u.email()));
            if (i < result.size() - 1) json.append(",");
            json.append("\n");
        }
        json.append("]");

        sendResponse(exchange, 200, "application/json", json.toString());
    }

    private static void handleCreateUser(HttpExchange exchange) throws IOException {
        String body = new String(exchange.getRequestBody().readAllBytes(), StandardCharsets.UTF_8);

        // 简单解析(实际应使用 JSON 库)
        String name = extractJsonValue(body, "name");
        String email = extractJsonValue(body, "email");

        if (name == null || email == null) {
            sendError(exchange, 400, "Missing name or email");
            return;
        }

        int newId = users.stream().mapToInt(User::id).max().orElse(0) + 1;
        User newUser = new User(newId, name, email);
        users.add(newUser);

        String json = """
            {
                "id": %d,
                "name": "%s",
                "email": "%s",
                "message": "User created successfully"
            }
            """.formatted(newUser.id(), newUser.name(), newUser.email());

        sendResponse(exchange, 201, "application/json", json);
    }

    // ============================================================
    //                    辅助方法
    // ============================================================

    private static void sendResponse(HttpExchange exchange, int code, String contentType, String body)
            throws IOException {
        byte[] bytes = body.getBytes(StandardCharsets.UTF_8);

        exchange.getResponseHeaders().set("Content-Type", contentType + "; charset=utf-8");
        exchange.sendResponseHeaders(code, bytes.length);

        try (OutputStream os = exchange.getResponseBody()) {
            os.write(bytes);
        }
    }

    private static void sendError(HttpExchange exchange, int code, String message) throws IOException {
        String json = """
            {
                "error": true,
                "code": %d,
                "message": "%s"
            }
            """.formatted(code, message);

        sendResponse(exchange, code, "application/json", json);
    }

    private static void logRequest(HttpExchange exchange) {
        String time = LocalDateTime.now().format(FORMATTER);
        String method = exchange.getRequestMethod();
        String path = exchange.getRequestURI().getPath();
        String remote = exchange.getRemoteAddress().toString();

        System.out.printf("[%s] %s %s from %s%n", time, method, path, remote);
    }

    private static Map<String, String> parseQuery(String query) {
        Map<String, String> params = new HashMap<>();
        if (query == null || query.isEmpty()) return params;

        for (String pair : query.split("&")) {
            String[] kv = pair.split("=", 2);
            if (kv.length == 2) {
                params.put(
                    URLDecoder.decode(kv[0], StandardCharsets.UTF_8),
                    URLDecoder.decode(kv[1], StandardCharsets.UTF_8)
                );
            }
        }
        return params;
    }

    private static String escapeJson(String s) {
        return s.replace("\\", "\\\\")
                .replace("\"", "\\\"")
                .replace("\n", "\\n")
                .replace("\r", "\\r")
                .replace("\t", "\\t");
    }

    private static String headersToJson(Headers headers) {
        StringBuilder sb = new StringBuilder("{");
        boolean first = true;
        for (Map.Entry<String, List<String>> entry : headers.entrySet()) {
            if (!first) sb.append(", ");
            sb.append("\"").append(entry.getKey()).append("\": \"")
              .append(String.join(", ", entry.getValue())).append("\"");
            first = false;
        }
        sb.append("}");
        return sb.toString();
    }

    private static String extractJsonValue(String json, String key) {
        // 简单的 JSON 值提取(实际应使用 JSON 库)
        String pattern = "\"" + key + "\"\\s*:\\s*\"([^\"]*)\"";
        java.util.regex.Matcher matcher = java.util.regex.Pattern.compile(pattern).matcher(json);
        return matcher.find() ? matcher.group(1) : null;
    }
}

record User(int id, String name, String email) {}

💬 讨论

使用 GitHub 账号登录后即可参与讨论

基于 MIT 许可发布