在 MiniTomcat 的开发过程中,我们需要将请求数据从底层的 Socket 输入输出流中抽象出来,以简化后续的业务处理与响应构建。通过设计 HttpServletRequestHttpServletResponse 类,我们可以为开发者提供更易用的请求和响应操作接口,其设计思路类似于标准的 Servlet API。


1. HttpServletRequest 封装设计

HttpServletRequest 是对客户端请求信息的抽象封装,主要包含请求方法、URL、头信息、参数等核心数据。

1.1 主要属性

  • 请求方法:如 GETPOST 等。
  • 请求路径:如 /index.html
  • 请求头:如 User-AgentAccept 等。
  • 请求参数:包含 URL 查询参数(GET)和表单数据(POST)。
  • Cookie 和 Session:用于跟踪用户状态(后续课程会进一步实现)。

1.2 主要方法

方法说明
getMethod()返回请求方法(如 GET)
getRequestURI()返回请求的 URI
getHeader(String name)获取指定名称的请求头的值
getParameter(String name)获取指定名称的请求参数的值
getCookies()获取请求中的 Cookie 列表

1.3 示例代码

public class HttpServletRequest {
    private String method;
    private String requestURI;
    private Map<String, String> headers = new HashMap<>();
    private Map<String, String> parameters = new HashMap<>();
    private List<Cookie> cookies = new ArrayList<>();

    // 构造函数,根据请求数据初始化各个属性
    public HttpServletRequest(InputStream inputStream) {
        parseRequest(inputStream);
    }

    private void parseRequest(InputStream inputStream) {
        // 解析请求行、请求头和参数逻辑
    }

    public String getMethod() { 
        return method; 
    }
    
    public String getRequestURI() { 
        return requestURI; 
    }
    
    public String getHeader(String name) { 
        return headers.get(name); 
    }
    
    public String getParameter(String name) { 
        return parameters.get(name); 
    }
    
    public List<Cookie> getCookies() { 
        return cookies; 
    }
}

2. HttpServletResponse 封装设计

HttpServletResponse 用于封装服务器端的响应数据,包括响应状态、头部信息和响应内容。

2.1 主要属性

  • 状态码:如 200404500 等。
  • 响应头:如 Content-TypeSet-Cookie 等。
  • 响应体:通常是 HTML、JSON 或文件内容。

2.2 主要方法

方法说明
setStatus(int statusCode)设置响应的状态码
setHeader(String name, String value)设置响应头
getWriter()获取 PrintWriter 对象,用于写入响应体内容
addCookie(Cookie cookie)设置 Cookie,用于保持会话状态

2.3 示例代码

public class HttpServletResponse {
    private int statusCode = 200;
    private Map<String, String> headers = new HashMap<>();
    private StringBuilder body = new StringBuilder();

    public void setStatus(int statusCode) { 
        this.statusCode = statusCode; 
    }
    
    public void setHeader(String name, String value) { 
        headers.put(name, value); 
    }
    
    public PrintWriter getWriter() {
        // 简化示意:实际实现中需正确处理流与编码
        return new PrintWriter(new StringWriter()); 
    }

    // 生成完整的 HTTP 响应数据
    public void sendResponse(OutputStream outputStream) throws IOException {
        PrintWriter writer = new PrintWriter(outputStream, true);
        writer.println("HTTP/1.1 " + statusCode + " OK");
        headers.forEach((key, value) -> writer.println(key + ": " + value));
        writer.println();
        writer.println(body.toString());
        writer.flush();
    }
}

3. 服务端应用示例

在服务器端,当接收到客户端连接时,我们可以创建 HttpServletRequestHttpServletResponse 实例进行处理。这种方式有效抽象了底层的流操作,使业务逻辑更加清晰。

Socket clientSocket = serverSocket.accept();

// 创建 HttpServletRequest 和 HttpServletResponse
HttpServletRequest request = new HttpServletRequest(clientSocket.getInputStream());
HttpServletResponse response = new HttpServletResponse();

// 设置响应头和内容
response.setStatus(200);
response.setHeader("Content-Type", "text/html");
PrintWriter writer = response.getWriter();
writer.println("<h1>Hello, World!</h1>");

// 发送响应
response.sendResponse(clientSocket.getOutputStream());
clientSocket.close();

4. 实践任务 📝

  1. 实现 HttpServletRequest 的构造方法:解析请求的输入流,提取请求行、请求头和参数。
  2. 实现 HttpServletResponsesendResponse 方法:构建 HTTP 响应字符串,并通过输出流发送。
  3. 编写测试代码:模拟客户端请求,验证 HttpServletRequestHttpServletResponse 是否能够正确封装请求与生成响应。

通过实现 HttpServletRequestHttpServletResponse,我们将为 MiniTomcat 提供更加标准化和易用的接口,为后续实现 Servlet 容器和业务处理逻辑奠定坚实基础。