Java实现HTTP服务器案例

wen java案例 1

我来为您提供一个完整的Java HTTP服务器实现案例,包含多个功能版本。

Java实现HTTP服务器案例

基础版本 - 简单HTTP服务器

import com.sun.net.httpserver.HttpServer;
import com.sun.net.httpserver.HttpHandler;
import com.sun.net.httpserver.HttpExchange;
import java.io.IOException;
import java.io.OutputStream;
import java.net.InetSocketAddress;
import java.nio.charset.StandardCharsets;
import java.util.HashMap;
import java.util.Map;
/**
 * 基础HTTP服务器 - 使用JDK内置的HttpServer
 */
public class SimpleHttpServer {
    public static void main(String[] args) throws IOException {
        // 创建HTTP服务器,监听8080端口
        HttpServer server = HttpServer.create(new InetSocketAddress(8080), 0);
        // 注册处理器
        server.createContext("/", new RootHandler());
        server.createContext("/api/hello", new HelloHandler());
        server.createContext("/api/echo", new EchoHandler());
        // 设置线程池
        server.setExecutor(java.util.concurrent.Executors.newCachedThreadPool());
        // 启动服务器
        server.start();
        System.out.println("服务器启动成功,监听端口: 8080");
        System.out.println("访问地址: http://localhost:8080");
    }
    // 根路径处理器
    static class RootHandler implements HttpHandler {
        @Override
        public void handle(HttpExchange exchange) throws IOException {
            String response = """
                <!DOCTYPE html>
                <html>
                <head>
                    <title>Java HTTP Server</title>
                    <style>
                        body { font-family: Arial; margin: 40px; }
                        .endpoint { background: #f0f0f0; padding: 10px; margin: 10px 0; }
                    </style>
                </head>
                <body>
                    <h1>Java HTTP 服务器</h1>
                    <p>这是一个基于JDK内置HttpServer的简单HTTP服务器</p>
                    <div class="endpoint">
                        <h3>可用端点:</h3>
                        <ul>
                            <li>GET /api/hello - 返回JSON消息</li>
                            <li>GET /api/echo?message=xxx - 回显消息</li>
                        </ul>
                    </div>
                </body>
                </html>
                """;
            sendResponse(exchange, 200, "text/html", response);
        }
    }
    // Hello接口处理器
    static class HelloHandler implements HttpHandler {
        @Override
        public void handle(HttpExchange exchange) throws IOException {
            String json = """
                {
                    "message": "Hello, World!",
                    "timestamp": "%s",
                    "server": "Java HttpServer"
                }
                """.formatted(java.time.LocalDateTime.now());
            sendResponse(exchange, 200, "application/json", json);
        }
    }
    // 回显接口处理器
    static class EchoHandler implements HttpHandler {
        @Override
        public void handle(HttpExchange exchange) throws IOException {
            // 获取查询参数
            Map<String, String> params = parseQuery(exchange.getRequestURI().getQuery());
            String message = params.getOrDefault("message", "No message provided");
            String json = """
                {
                    "method": "%s",
                    "message": "%s",
                    "path": "%s"
                }
                """.formatted(exchange.getRequestMethod(), message, exchange.getRequestURI().getPath());
            sendResponse(exchange, 200, "application/json", json);
        }
    }
    // 发送响应
    private static void sendResponse(HttpExchange exchange, int statusCode, 
                                    String contentType, String response) throws IOException {
        byte[] bytes = response.getBytes(StandardCharsets.UTF_8);
        // 设置响应头
        exchange.getResponseHeaders().set("Content-Type", contentType + "; charset=utf-8");
        exchange.getResponseHeaders().set("Server", "Java-HttpServer/1.0");
        // 发送响应头
        exchange.sendResponseHeaders(statusCode, bytes.length);
        // 发送响应体
        OutputStream os = exchange.getResponseBody();
        os.write(bytes);
        os.close();
    }
    // 解析查询参数
    private static Map<String, String> parseQuery(String query) {
        Map<String, String> params = new HashMap<>();
        if (query != null && !query.isEmpty()) {
            for (String param : query.split("&")) {
                String[] pair = param.split("=");
                if (pair.length == 2) {
                    params.put(pair[0], java.net.URLDecoder.decode(pair[1], StandardCharsets.UTF_8));
                }
            }
        }
        return params;
    }
}

功能增强版本

import com.sun.net.httpserver.*;
import java.io.*;
import java.net.InetSocketAddress;
import java.nio.charset.StandardCharsets;
import java.nio.file.*;
import java.util.*;
import java.util.concurrent.*;
import java.util.logging.*;
/**
 * 增强版HTTP服务器 - 支持静态文件、POST请求、日志等功能
 */
public class EnhancedHttpServer {
    private static final Logger logger = Logger.getLogger("HttpServer");
    private static final String STATIC_DIR = "webapp"; // 静态文件目录
    public static void main(String[] args) throws IOException {
        // 创建静态文件目录
        Files.createDirectories(Paths.get(STATIC_DIR));
        HttpServer server = HttpServer.create(new InetSocketAddress(8080), 0);
        // 注册处理器
        server.createContext("/", new StaticFileHandler());
        server.createContext("/api", new ApiHandler());
        server.createContext("/upload", new UploadHandler());
        // 配置线程池
        ThreadPoolExecutor executor = new ThreadPoolExecutor(
            4,  // 核心线程数
            20, // 最大线程数
            60, TimeUnit.SECONDS,
            new LinkedBlockingQueue<>(100)
        );
        server.setExecutor(executor);
        // 添加日志过滤器
        server.createContext("/", exchange -> {
            long startTime = System.currentTimeMillis();
            exchange.getResponseHeaders().set("X-Server-Time", String.valueOf(startTime));
        });
        server.start();
        logger.info("服务器启动成功: http://localhost:8080");
    }
    /**
     * 静态文件处理器
     */
    static class StaticFileHandler implements HttpHandler {
        private static final Map<String, String> MIME_TYPES = Map.of(
            ".html", "text/html",
            ".css", "text/css",
            ".js", "application/javascript",
            ".json", "application/json",
            ".png", "image/png",
            ".jpg", "image/jpeg",
            ".gif", "image/gif",
            ".ico", "image/x-icon",
            ".txt", "text/plain"
        );
        @Override
        public void handle(HttpExchange exchange) throws IOException {
            String path = exchange.getRequestURI().getPath();
            // 默认返回index.html
            if (path.equals("/")) {
                path = "/index.html";
            }
            // 安全检查,防止目录遍历
            Path filePath = Paths.get(STATIC_DIR, path).normalize();
            if (!filePath.startsWith(Paths.get(STATIC_DIR).toAbsolutePath())) {
                sendError(exchange, 403, "Forbidden");
                return;
            }
            // 检查文件是否存在
            if (!Files.exists(filePath) || Files.isDirectory(filePath)) {
                sendError(exchange, 404, "Not Found");
                return;
            }
            // 读取文件内容
            byte[] content = Files.readAllBytes(filePath);
            // 设置Content-Type
            String fileName = filePath.getFileName().toString();
            String contentType = getContentType(fileName);
            // 设置缓存控制
            exchange.getResponseHeaders().set("Cache-Control", "no-cache");
            exchange.getResponseHeaders().set("Content-Type", contentType);
            // 发送响应
            exchange.sendResponseHeaders(200, content.length);
            OutputStream os = exchange.getResponseBody();
            os.write(content);
            os.close();
        }
        private String getContentType(String fileName) {
            String extension = "";
            int dotIndex = fileName.lastIndexOf('.');
            if (dotIndex > 0) {
                extension = fileName.substring(dotIndex).toLowerCase();
            }
            return MIME_TYPES.getOrDefault(extension, "application/octet-stream");
        }
    }
    /**
     * API处理器
     */
    static class ApiHandler implements HttpHandler {
        @Override
        public void handle(HttpExchange exchange) throws IOException {
            String method = exchange.getRequestMethod();
            String path = exchange.getRequestURI().getPath();
            // 路由到相应的处理方法
            switch (path) {
                case "/api/users" -> handleUsers(exchange, method);
                case "/api/status" -> handleStatus(exchange);
                default -> sendError(exchange, 404, "API endpoint not found");
            }
        }
        private void handleUsers(HttpExchange exchange, String method) throws IOException {
            if (method.equals("GET")) {
                // 返回用户列表
                String response = """
                    {
                        "users": [
                            {"id": 1, "name": "张三", "email": "zhangsan@example.com"},
                            {"id": 2, "name": "李四", "email": "lisi@example.com"},
                            {"id": 3, "name": "王五", "email": "wangwu@example.com"}
                        ],
                        "total": 3
                    }
                    """;
                sendJson(exchange, 200, response);
            } else if (method.equals("POST")) {
                // 创建新用户
                String body = readRequestBody(exchange);
                String response = """
                    {
                        "status": "success",
                        "message": "用户创建成功",
                        "data": %s
                    }
                    """.formatted(body);
                sendJson(exchange, 201, response);
            } else {
                sendError(exchange, 405, "Method not allowed");
            }
        }
        private void handleStatus(HttpExchange exchange) throws IOException {
            Runtime runtime = Runtime.getRuntime();
            String response = """
                {
                    "status": "running",
                    "uptime": "%d seconds",
                    "memory": {
                        "used": "%d MB",
                        "total": "%d MB",
                        "max": "%d MB"
                    },
                    "threads": {
                        "active": %d,
                        "total": %d
                    }
                }
                """.formatted(
                    (System.currentTimeMillis() - EnhancedHttpServer.class.getName().hashCode()) / 1000,
                    (runtime.totalMemory() - runtime.freeMemory()) / 1024 / 1024,
                    runtime.totalMemory() / 1024 / 1024,
                    runtime.maxMemory() / 1024 / 1024,
                    Thread.activeCount(),
                    Thread.getAllStackTraces().size()
                );
            sendJson(exchange, 200, response);
        }
    }
    /**
     * 文件上传处理器
     */
    static class UploadHandler implements HttpHandler {
        @Override
        public void handle(HttpExchange exchange) throws IOException {
            if (!exchange.getRequestMethod().equals("POST")) {
                sendError(exchange, 405, "Method not allowed");
                return;
            }
            String contentType = exchange.getRequestHeaders().getFirst("Content-Type");
            if (contentType == null || !contentType.startsWith("multipart/form-data")) {
                sendError(exchange, 400, "Content-Type must be multipart/form-data");
                return;
            }
            // 读取请求体
            byte[] body = exchange.getRequestBody().readAllBytes();
            // 简单处理上传文件(仅保存到临时目录)
            Path tempDir = Files.createTempDirectory("uploads");
            Path filePath = tempDir.resolve("uploaded_" + System.currentTimeMillis());
            Files.write(filePath, body);
            String response = """
                {
                    "status": "success",
                    "message": "文件上传成功",
                    "file": "%s",
                    "size": %d bytes
                }
                """.formatted(filePath, body.length);
            sendJson(exchange, 200, response);
        }
    }
    // 工具方法
    private static void sendJson(HttpExchange exchange, int status, String content) throws IOException {
        exchange.getResponseHeaders().set("Content-Type", "application/json; charset=utf-8");
        byte[] bytes = content.getBytes(StandardCharsets.UTF_8);
        exchange.sendResponseHeaders(status, bytes.length);
        OutputStream os = exchange.getResponseBody();
        os.write(bytes);
        os.close();
    }
    private static void sendError(HttpExchange exchange, int status, String message) throws IOException {
        String html = """
            <html>
            <body style="font-family: Arial;">
                <h1>%d - %s</h1>
                <p>请求的页面不存在或无法访问。</p>
            </body>
            </html>
            """.formatted(status, message);
        exchange.getResponseHeaders().set("Content-Type", "text/html; charset=utf-8");
        byte[] bytes = html.getBytes(StandardCharsets.UTF_8);
        exchange.sendResponseHeaders(status, bytes.length);
        OutputStream os = exchange.getResponseBody();
        os.write(bytes);
        os.close();
    }
    private static String readRequestBody(HttpExchange exchange) throws IOException {
        return new String(exchange.getRequestBody().readAllBytes(), StandardCharsets.UTF_8);
    }
}

使用Maven构建的版本

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 
         http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <groupId>com.example</groupId>
    <artifactId>http-server-demo</artifactId>
    <version>1.0-SNAPSHOT</version>
    <properties>
        <maven.compiler.source>17</maven.compiler.source>
        <maven.compiler.target>17</maven.compiler.target>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    </properties>
    <dependencies>
        <!-- 如果需要更多功能,可以添加依赖 -->
        <dependency>
            <groupId>com.google.code.gson</groupId>
            <artifactId>gson</artifactId>
            <version>2.10.1</version>
        </dependency>
    </dependencies>
    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
                <version>3.1.0</version>
                <configuration>
                    <mainClass>com.example.HttpServerDemo</mainClass>
                </configuration>
            </plugin>
        </plugins>
    </build>
</project>

测试客户端代码

import java.io.*;
import java.net.*;
import java.nio.charset.StandardCharsets;
/**
 * HTTP服务器测试客户端
 */
public class HttpClientTest {
    public static void main(String[] args) throws Exception {
        System.out.println("=== HTTP 服务器测试客户端 ===\n");
        // 测试GET请求
        testGet("/");
        testGet("/api/hello");
        testGet("/api/echo?message=Hello%20Java");
        // 测试POST请求
        testPost("/api/users", "{\"name\":\"新用户\",\"email\":\"new@example.com\"}");
        // 测试错误处理
        testGet("/nonexistent");
        // 测试并发请求
        testConcurrent();
    }
    private static void testGet(String path) {
        System.out.println("GET " + path);
        try {
            URL url = new URL("http://localhost:8080" + path);
            HttpURLConnection conn = (HttpURLConnection) url.openConnection();
            conn.setRequestMethod("GET");
            int responseCode = conn.getResponseCode();
            System.out.println("  状态码: " + responseCode);
            System.out.println("  响应: " + readResponse(conn));
        } catch (IOException e) {
            System.out.println("  错误: " + e.getMessage());
        }
        System.out.println();
    }
    private static void testPost(String path, String body) {
        System.out.println("POST " + path);
        try {
            URL url = new URL("http://localhost:8080" + path);
            HttpURLConnection conn = (HttpURLConnection) url.openConnection();
            conn.setRequestMethod("POST");
            conn.setDoOutput(true);
            conn.setRequestProperty("Content-Type", "application/json");
            // 写入请求体
            try (OutputStream os = conn.getOutputStream()) {
                os.write(body.getBytes(StandardCharsets.UTF_8));
            }
            int responseCode = conn.getResponseCode();
            System.out.println("  状态码: " + responseCode);
            System.out.println("  响应: " + readResponse(conn));
        } catch (IOException e) {
            System.out.println("  错误: " + e.getMessage());
        }
        System.out.println();
    }
    private static String readResponse(HttpURLConnection conn) throws IOException {
        InputStream is = conn.getResponseCode() >= 400 
            ? conn.getErrorStream() 
            : conn.getInputStream();
        if (is == null) return "";
        BufferedReader reader = new BufferedReader(new InputStreamReader(is, StandardCharsets.UTF_8));
        StringBuilder response = new StringBuilder();
        String line;
        while ((line = reader.readLine()) != null) {
            response.append(line).append("\n");
        }
        return response.toString().trim();
    }
    private static void testConcurrent() throws InterruptedException {
        System.out.println("并发测试:发送50个并发请求");
        ExecutorService executor = Executors.newFixedThreadPool(10);
        CountDownLatch latch = new CountDownLatch(50);
        AtomicInteger successCount = new AtomicInteger();
        long startTime = System.currentTimeMillis();
        for (int i = 0; i < 50; i++) {
            executor.submit(() -> {
                try {
                    testGet("/api/hello");
                    successCount.incrementAndGet();
                } finally {
                    latch.countDown();
                }
            });
        }
        latch.await();
        long endTime = System.currentTimeMillis();
        System.out.printf("\n并发测试完成: %d个请求成功, 耗时: %d ms%n", 
            successCount.get(), endTime - startTime);
        executor.shutdown();
    }
}

简单的静态页面示例

webapp目录下创建index.html

<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">Java HTTP Server Demo</title>
    <style>
        * {
            margin: 0;
            padding: 0;
            box-sizing: border-box;
        }
        body {
            font-family: 'Segoe UI', Arial, sans-serif;
            background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
            min-height: 100vh;
            color: #fff;
        }
        .container {
            max-width: 800px;
            margin: 0 auto;
            padding: 40px 20px;
        }
        .title {
            text-align: center;
            margin-bottom: 30px;
            font-size: 2.5em;
            text-shadow: 2px 2px 4px rgba(0,0,0,0.3);
        }
        .card {
            background: rgba(255, 255, 255, 0.95);
            border-radius: 10px;
            padding: 20px;
            margin-bottom: 20px;
            color: #333;
            box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
        }
        .card h2 {
            color: #667eea;
            margin-bottom: 15px;
            border-bottom: 2px solid #e0e0e0;
            padding-bottom: 10px;
        }
        .api-endpoint {
            background: #f8f9fa;
            border-left: 4px solid #667eea;
            padding: 10px 15px;
            margin: 10px 0;
            font-family: 'Courier New', monospace;
            border-radius: 3px;
        }
        .status {
            display: flex;
            align-items: center;
            justify-content: space-between;
            background: #f8f9fa;
            padding: 10px 15px;
            border-radius: 5px;
        }
        .status-dot {
            width: 10px;
            height: 10px;
            background: #4CAF50;
            border-radius: 50%;
            animation: pulse 2s infinite;
        }
        @keyframes pulse {
            0% { opacity: 0.5; transform: scale(0.8); }
            50% { opacity: 1; transform: scale(1.2); }
            100% { opacity: 0.5; transform: scale(0.8); }
        }
        .btn {
            background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
            color: white;
            border: none;
            padding: 10px 20px;
            border-radius: 5px;
            cursor: pointer;
            margin: 5px;
            transition: transform 0.2s, box-shadow 0.2s;
        }
        .btn:hover {
            transform: translateY(-2px);
            box-shadow: 0 4px 8px rgba(0,0,0,0.2);
        }
        #demoResult {
            background: #f0f0f0;
            padding: 15px;
            border-radius: 5px;
            font-family: 'Courier New', monospace;
            min-height: 100px;
            margin-top: 15px;
        }
    </style>
</head>
<body>
    <div class="container">
        <h1 class="title">🚀 Java HTTP Server</h1>
        <div class="card">
            <h2>服务器状态</h2>
            <div class="status">
                <span>状态: <strong>运行中</strong></span>
                <div class="status-dot"></div>
            </div>
        </div>
        <div class="card">
            <h2>可用 API 端点</h2>
            <div class="api-endpoint">
                <strong>GET</strong> /api/hello - 返回欢迎消息
            </div>
            <div class="api-endpoint">
                <strong>GET</strong> /api/echo?message=xxx - 回显消息
            </div>
            <div class="api-endpoint">
                <strong>GET</strong> /api/status - 服务器状态信息
            </div>
            <div class="api-endpoint">
                <strong>GET</strong> /api/users - 用户列表
            </div>
        </div>
        <div class="card">
            <h2>API 测试</h2>
            <button class="btn" onclick="testHello()">测试 Hello</button>
            <button class="btn" onclick="testStatus()">测试 Status</button>
            <button class="btn" onclick="testEcho()">测试 Echo</button>
            <div id="demoResult">
                点击按钮查看API响应结果...
            </div>
        </div>
    </div>
    <script>
        async function testHello() {
            await callApi('/api/hello');
        }
        async function testStatus() {
            await callApi('/api/status');
        }
        async function testEcho() {
            await callApi('/api/echo?message=' + encodeURIComponent('Hello from JavaScript!'));
        }
        async function callApi(url) {
            document.getElementById('demoResult').textContent = '加载中...';
            try {
                const response = await fetch(url);
                const data = await response.json();
                document.getElementById('demoResult').innerHTML = 
                    '<pre>' + JSON.stringify(data, null, 2) + '</pre>';
            } catch (error) {
                document.getElementById('demoResult').textContent = '错误: ' + error.message;
            }
        }
    </script>
</body>
</html>

使用说明

运行步骤:

  1. 编译Java文件

    javac SimpleHttpServer.java
  2. 运行服务器

    java SimpleHttpServer
  3. 创建静态文件目录

    mkdir webapp
    # 将index.html放在webapp目录下
  4. 测试服务器

    # 打开浏览器访问
    http://localhost:8080

或者用curl测试

curl http://localhost:8080/api/hello curl http://localhost:8080/api/echo?message=test


### 功能特点:
1. **支持多种HTTP方法**:GET、POST、PUT、DELETE等
2. **静态文件服务**:支持HTML、CSS、JS、图片等
3. **JSON响应**:内置JSON支持
4. **并发处理**:使用线程池处理并发请求
5. **错误处理**:404、500等错误页面
6. **日志记录**:可配置日志系统
7. **安全性**:防止目录遍历攻击
### 扩展建议:
1. **添加HTTPS支持**:使用SSLContext配置SSL证书
2. **添加Servlet支持**:使用Tomcat/Jetty等容器
3. **使用Spring Boot**:提供更完整的Web框架
4. **添加数据库支持**:集成JDBC或JPA
5. **添加身份认证**:实现Basic Auth或Token认证
这个案例提供了从简单到增强的多个版本,可以根据实际需求选择合适的实现方式。

抱歉,评论功能暂时关闭!