我们将分步进行,从最基础的服务器启动,到解析请求、处理请求,最后返回响应。

核心概念回顾
在开始编码前,我们先回顾一下几个关键概念:
- Socket (套接字):是网络编程的 API,它提供了两台计算机之间进行通信的端点,在 Java 中,
java.net.ServerSocket用于服务器端,等待客户端连接;java.net.Socket用于客户端,或服务器端与已连接的客户端通信。 - HTTP (超文本传输协议):是 Web 的基础协议,它是一种基于文本的、无状态的请求/响应协议,一个典型的 HTTP 交互包括:
- 客户端请求:客户端(如浏览器)向服务器发送一个请求报文,包含请求方法(如
GET,POST)、路径、HTTP 版本和一系列请求头。 - 服务器响应:服务器解析请求,处理后,向客户端返回一个响应报文,包含状态码(如
200 OK,404 Not Found)、响应头和响应体(通常是 HTML 内容)。
- 客户端请求:客户端(如浏览器)向服务器发送一个请求报文,包含请求方法(如
步骤一:创建一个基础服务器(仅接受连接)
我们先创建一个最简单的服务器,它只负责监听端口并接受客户端连接,但不做任何处理。
import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;
public class SimpleHttpServer {
// 定义服务器监听的端口号
private static final int PORT = 8080;
public static void main(String[] args) {
// 使用 try-with-resources 确保 ServerSocket 被正确关闭
try (ServerSocket serverSocket = new ServerSocket(PORT)) {
System.out.println("服务器启动,监听端口: " + PORT);
// 进入无限循环,持续等待客户端连接
while (true) {
// accept() 方法会阻塞,直到一个客户端连接进来
Socket clientSocket = serverSocket.accept();
System.out.println("新的客户端连接: " + clientSocket.getInetAddress().getHostAddress());
// 为了不阻塞主线程处理下一个连接,我们为每个客户端连接创建一个新线程
new Thread(new ClientHandler(clientSocket)).start();
}
} catch (IOException e) {
System.err.println("服务器启动失败或发生 I/O 错误: " + e.getMessage());
e.printStackTrace();
}
}
}
// 客户端连接处理器
class ClientHandler implements Runnable {
private final Socket clientSocket;
public ClientHandler(Socket socket) {
this.clientSocket = socket;
}
@Override
public void run() {
// 在这里我们将处理客户端的请求和响应
System.out.println(Thread.currentThread().getName() + " 正在处理客户端: " + clientSocket.getInetAddress());
// 为了演示,我们暂时只打印信息并关闭连接
try {
// 获取输入流,可以读取客户端发送的数据
// clientSocket.getInputStream();
// 获取输出流,可以向客户端发送数据
// clientSocket.getOutputStream();
System.out.println("处理完毕,关闭连接。");
clientSocket.close();
} catch (IOException e) {
System.err.println("处理客户端时发生错误: " + e.getMessage());
}
}
}
如何运行:
- 将代码保存为
SimpleHttpServer.java。 - 编译:
javac SimpleHttpServer.java - 运行:
java SimpleHttpServer - 你会看到控制台输出 "服务器启动,监听端口: 8080"。
- 打开浏览器,访问
http://localhost:8080,然后观察服务器控制台的输出。
步骤二:解析 HTTP 请求
我们来完善 ClientHandler,使其能够读取客户端(浏览器)发送的原始 HTTP 请求报文。

HTTP 请求报文由三部分组成:请求行、请求头、请求体,对于 GET 请求,通常没有请求体,我们可以按行读取,直到遇到一个空行(\r\n),这标志着请求头的结束。
// 在 ClientHandler 的 run() 方法中更新以下代码
@Override
public void run() {
try (
// 使用 try-with-resources 自动关闭流
BufferedReader in = new BufferedReader(new InputStreamReader(clientSocket.getInputStream()));
PrintWriter out = new PrintWriter(clientSocket.getOutputStream(), true) // autoFlush=true
) {
System.out.println(Thread.currentThread().getName() + " 正在处理客户端: " + clientSocket.getInetAddress());
// 1. 读取并解析 HTTP 请求
String requestLine = in.readLine();
if (requestLine == null) {
return; // 客户端可能断开连接
}
System.out.println("收到请求行: " + requestLine);
// 解析请求行,格式为 "METHOD PATH PROTOCOL"
String[] requestParts = requestLine.split(" ");
if (requestParts.length < 3) {
sendErrorResponse(out, 400, "Bad Request");
return;
}
String method = requestParts[0];
String path = requestParts[1];
String httpVersion = requestParts[2];
System.out.println("请求方法: " + method);
System.out.println("请求路径: " + path);
System.out.println("HTTP版本: " + httpVersion);
// 读取请求头,直到遇到空行
String headerLine;
while ((headerLine = in.readLine()) != null && !headerLine.isEmpty()) {
System.out.println("请求头: " + headerLine);
}
// 2. 处理请求并生成响应
// ... (下一步实现)
// 3. 发送响应
// ... (下一步实现)
System.out.println("处理完毕,关闭连接。");
} catch (IOException e) {
System.err.println("处理客户端时发生错误: " + e.getMessage());
}
}
// 辅助方法:发送错误响应
private void sendErrorResponse(PrintWriter out, int statusCode, String statusMessage) {
out.println("HTTP/1.1 " + statusCode + " " + statusMessage);
out.println("Content-Type: text/html");
out.println("Connection: close");
out.println(); // 空行,分隔响应头和响应体
out.println("<html><body><h1>" + statusCode + " " + statusMessage + "</h1></body></html>");
}
运行并测试:
再次运行服务器,然后用浏览器访问 http://localhost:8080,你会看到服务器控制台打印出了详细的请求信息,包括 GET / HTTP/1.1 和各种请求头(如 Host, User-Agent 等)。
步骤三:处理请求并发送 HTTP 响应
我们根据请求的路径,生成相应的 HTTP 响应,我们将实现一个非常简单的路由:访问 返回 "Hello, World!",访问 /about 返回 "About Page",其他路径返回 404 Not Found。
// 在 ClientHandler 的 run() 方法中,在解析完请求后添加以下代码
// 2. 处理请求并生成响应
String responseContent;
String contentType;
int statusCode;
String statusMessage;
if ("/".equals(path)) {
responseContent = "<html><head><title>Home</title></head><body><h1>Hello, World!</h1><p>欢迎来到我的 Java HTTP 服务器!</p></body></html>";
contentType = "text/html";
statusCode = 200;
statusMessage = "OK";
} else if ("/about".equals(path)) {
responseContent = "<html><head><title>About</title></head><body><h1>About Page</h1><p>这是一个用 Java Socket 实现的简单 HTTP 服务器。</p></body></html>";
contentType = "text/html";
statusCode = 200;
statusMessage = "OK";
} else {
responseContent = "<html><head><title>404 Not Found</title></head><body><h1>404 Not Found</h1><p>你请求的页面不存在。</p></body></html>";
contentType = "text/html";
statusCode = 404;
statusMessage = "Not Found";
}
// 3. 发送响应
out.println("HTTP/1.1 " + statusCode + " " + statusMessage);
out.println("Content-Type: " + contentType);
out.println("Content-Length: " + responseContent.getBytes(StandardCharsets.UTF_8).length);
out.println("Connection: close"); // 告诉客户端连接将在响应后关闭
out.println(); // 空行,非常重要,分隔响应头和响应体
out.println(responseContent); // 发送响应体
别忘了添加 import:
import java.nio.charset.StandardCharsets;
完整代码
将所有部分整合起来,这就是一个功能完整的、简单的 Java HTTP 服务器。
import java.io.*; import java.net.ServerSocket; import java.net.Socket; import java.nio.charset
