You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用Jetty搭建stub server测试HTTP应用的方案咨询

方案结论

使用Jetty的HttpParser和HttpTester搭建测试桩服务是完全可行的方案。这两个组件是Jetty实现HTTP协议层的核心底层工具,不需要启动完整的Jetty Web容器,就能完成HTTP报文解析、生成的全部能力,非常适合单元测试场景下的轻量桩搭建,完全匹配你提出的「解析请求、返回预设响应、内省请求内容」三个核心需求。

实现逻辑说明
  • 请求解析:HttpParser可以直接对接Socket输入流,自动完成请求行、请求头、请求体的标准HTTP协议解析,不需要手动处理报文格式、编码、分块等细节,解析完成后可以直接读取所有请求字段做校验
  • 响应生成:HttpTester提供了链式API快速构造标准HTTP响应报文,生成的字节流可以直接写入Socket输出流返回给客户端,不需要手动拼接响应报文格式
测试代码补全示例

以下是补全了你示例代码中空缺逻辑的可运行版本:

import org.eclipse.jetty.http.*;
import org.eclipse.jetty.http.parser.HttpParser;
import org.eclipse.jetty.http.parser.RequestHandler;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.ServerSocket;
import java.net.Socket;
import java.nio.ByteBuffer;
import java.nio.charset.StandardCharsets;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import org.testng.annotations.*;
import static org.testng.Assert.assertEquals;

public class MyTestSuite {
  ServerSocket serverSock;
  ExecutorService executor;

  @BeforeMethod
  public void setupServerSocket() throws IOException {
    serverSock = new ServerSocket(0);
    executor = Executors.newSingleThreadExecutor();
  }

  @AfterMethod
  public void teardownServerSocket() throws IOException {
    serverSock.close();
    executor.shutdownNow();
  }

  @Test
  public void myTest() throws Exception {
    Future<HttpField> result = executor.submit(() -> {
      try (Socket sock = serverSock.accept();
           InputStream in = sock.getInputStream();
           OutputStream out = sock.getOutputStream()) {
        // 初始化请求承载对象
        HttpTester.Request request = HttpTester.newRequest();
        // 初始化HTTP解析器
        HttpParser parser = new HttpParser(new RequestHandler() {
          @Override
          public void content(ByteBuffer buffer) {
            // 缓存请求体内容
            request.setContent(buffer);
          }
        });
        
        // 从Socket流读取数据喂给解析器,直到请求解析完成
        byte[] readBuf = new byte[2048];
        int readLen;
        while ((readLen = in.read(readBuf)) != -1) {
          parser.parse(ByteBuffer.wrap(readBuf, 0, readLen));
          if (parser.isComplete()) {
            break;
          }
        }
        // 将解析结果填充到request对象
        parser.fillRequestFromParser(request);

        // 构造预设桩响应
        HttpTester.Response response = HttpTester.newResponse();
        response.setStatus(HttpStatus.OK_200);
        response.setContentType("application/json;charset=utf-8");
        response.setContent("{\"status\":\"ok\"}".getBytes(StandardCharsets.UTF_8));
        // 写入响应到客户端
        out.write(response.generate());
        out.flush();

        // 返回待校验的请求头字段
        return request.getField(HttpHeader.CONTENT_TYPE);
      }
    });

    // 被测客户端需要传入当前桩服务的监听端口
    int stubPort = serverSock.getLocalPort();
    clientUnderTest.methodUnderTest(stubPort);
    HttpField field = result.get();

    assertEquals(field.getHeader(), HttpHeader.CONTENT_TYPE);
    assertEquals(field.getValue(), "application/json");
  }
}
使用注意事项
  • 上述实现是单连接单请求的极简模式,启动无额外开销,完全适配单元测试的快速执行需求
  • 如果后续需要支持长连接、HTTPS、分块传输编码等复杂HTTP特性,不需要重写逻辑,直接切换为Jetty完整Server注册测试Handler即可,API使用逻辑保持一致
  • 如果被测客户端会发送大体积请求体,适当调大读取缓冲区的大小,避免报文截断导致解析失败
  • 测试结束后记得关闭线程池和Socket,避免端口占用影响后续测试用例执行

内容的提问来源于stack exchange,提问作者warownia1

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.29 16:36:16