8.3 Java HTTP

HTTP协议 参考 1.2http协议-CSDN博客文章浏览阅读1.8k次,点赞68次,收藏23次。HTTP 用socket发送http响应给浏览器https://chxii.blog.csdn.net/article/details/146284464?spm=1011.2415.3001.5331

 java 使用ServerSocket 根据 浏览器 请求,做出响应

基于 Java 的简单 HTTP 服务器实现,响应 GET 请求,返回固定简单html,并支持静态资源(如 favicon.ico)的返回。


关键技术点

  • HTTP 协议解析

    • 手动读取并解析 HTTP 请求行和请求头。
    • 支持基础的 URL 路径判断(如 /favicon.ico)。
  • 字符编码处理

    • 使用 StandardCharsets.UTF_8 统一处理输入输出编码,避免乱码问题。
  • 时区与时间格式化

    • 使用 ZonedDateTime 和 ZoneId.of("UTC") 构造符合 RFC 1123 标准的日期头字段。
  • 静态资源服务

    • 提供对 favicon.ico 的特殊处理,支持二进制文件发送。
  • 异常处理机制

    • 捕获并打印服务器启动和请求处理中的异常信息。
    • 返回对应的错误页面(如 405、500)。
启动方式:

java Test1

默认监听端口:8080
默认网站根目录:www/
需确保 www/favicon.ico 存在,否则将返回空响应。

测试访问:
  • 访问 http://localhost:8080 将显示欢迎语句。

该项目用途:

  • 学习 HTTP 协议底层原理

项目代码:

import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;
import java.nio.charset.StandardCharsets;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.TimeZone;
import java.time.ZoneId;
import java.time.ZonedDateTime;

public class Test1 {
    private static final int PORT = 8080;
    private static final String ROOT_DIR = "www";
    private static final String FAVICON_PATH = ROOT_DIR + "/favicon.ico";

    public static void main(String[] args) {
        try (ServerSocket serverSocket = new ServerSocket(PORT)) {
            System.out.println("服务器启动,监听端口: " + PORT);
            
            while (true) {
                try (Socket clientSocket = serverSocket.accept()) {
                    System.out.println("客户端连接: " + clientSocket.getInetAddress());
                    
                    BufferedReader in = new BufferedReader(
                        new InputStreamReader(clientSocket.getInputStream(), StandardCharsets.UTF_8));
                    PrintWriter out = new PrintWriter(
                        new OutputStreamWriter(clientSocket.getOutputStream(), StandardCharsets.UTF_8), true);
                    
                    String requestLine = in.readLine();
                    if (requestLine == null) continue;
                    
                    System.out.println("请求行: " + requestLine);
                    
                    String[] requestParts = requestLine.split(" ");
                    if (requestParts.length < 2) continue;
                    
                    String method = requestParts[0];
                    String path = requestParts[1];
                    
                    // 读取请求头(忽略)
                    String headerLine;
                    while ((headerLine = in.readLine()) != null && !headerLine.isEmpty()) {
                        System.out.println("请求头: " + headerLine);
                    }
                    
                    if ("GET".equalsIgnoreCase(method)) {
                        //handleGetRequest(path, out, clientSocket.getOutputStream());
                         // 特别处理favicon.ico
                        if ("/favicon.ico".equals(path)) {
                            handleFaviconRequest(out,  clientSocket.getOutputStream());
                            return;
                        }
                        sendResponse(out, 200, "text/html", "

欢迎使用虚拟线程Web服务器

"); } else { sendResponse(out, 405, "Method Not Allowed", "该方法不被支持"); } } catch (IOException e) { System.err.println("处理请求时出错: " + e.getMessage()); } } } catch (IOException e) { System.err.println("服务器启动失败: " + e.getMessage()); } } private static void handleFaviconRequest(PrintWriter out, OutputStream rawOut) { File favicon = new File(FAVICON_PATH); if (favicon.exists() && favicon.isFile()) { try { // 使用ZonedDateTime并指定时区为UTC String date = ZonedDateTime.now(ZoneId.of("UTC")) .format(DateTimeFormatter.RFC_1123_DATE_TIME); // 发送响应头 StringBuilder responseHeader = new StringBuilder(); responseHeader.append("HTTP/1.1 200 OK\r\n"); responseHeader.append("Date: ").append(date).append("\r\n"); responseHeader.append("Server: SimpleTCPServer/1.0\r\n"); responseHeader.append("Content-Type: image/x-icon\r\n"); responseHeader.append("Content-Length: ").append(favicon.length()).append("\r\n"); responseHeader.append("Connection: close\r\n"); responseHeader.append("\r\n"); // 发送响应头 out.print(responseHeader.toString()); out.flush(); // 发送图标二进制数据 try (FileInputStream fis = new FileInputStream(favicon)) { byte[] buffer = new byte[4096]; int bytesRead; while ((bytesRead = fis.read(buffer)) != -1) { rawOut.write(buffer, 0, bytesRead); } } rawOut.flush(); } catch (IOException e) { sendResponse(out, 500, "Internal Server Error", "服务器内部错误"); } } else { // 如果没有提供图标,返回一个空的图标响应 sendEmptyFaviconResponse(out); } } private static void sendEmptyFaviconResponse(PrintWriter out) { // 使用ZonedDateTime并指定时区为UTC String date = ZonedDateTime.now(ZoneId.of("UTC")) .format(DateTimeFormatter.RFC_1123_DATE_TIME); String response = """ HTTP/1.1 200 OK Date: %s Server: SimpleTCPServer/1.0 Content-Type: image/x-icon Content-Length: 0 Connection: close """.formatted(date); out.print(response); out.flush(); } private static void sendResponse(PrintWriter out, int statusCode, String contentType, String content) { String statusLine = "HTTP/1.1 " + statusCode + " " + getStatusMessage(statusCode); // 使用ZonedDateTime并指定时区为UTC String date = ZonedDateTime.now(ZoneId.of("UTC")) .format(DateTimeFormatter.RFC_1123_DATE_TIME); StringBuilder response = new StringBuilder(); response.append(statusLine).append("\r\n"); response.append("Date: ").append(date).append("\r\n"); response.append("Server: SimpleTCPServer/1.0\r\n"); response.append("Content-Type: ").append(contentType).append("; charset=utf-8\r\n"); response.append("Content-Length: ").append(content.getBytes().length).append("\r\n"); response.append("Connection: close\r\n"); response.append("\r\n"); response.append(content); out.print(response.toString()); out.flush(); } private static String getStatusMessage(int statusCode) { return switch (statusCode) { case 200 -> "OK"; case 404 -> "Not Found"; case 405 -> "Method Not Allowed"; case 500 -> "Internal Server Error"; default -> "Unknown Status"; }; } }

你可能感兴趣的:(java,http,java)