我来为您提供一个完整的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>
使用说明
运行步骤:
-
编译Java文件:
javac SimpleHttpServer.java
-
运行服务器:
java SimpleHttpServer
-
创建静态文件目录:
mkdir webapp # 将index.html放在webapp目录下
-
测试服务器:
# 打开浏览器访问 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认证
这个案例提供了从简单到增强的多个版本,可以根据实际需求选择合适的实现方式。