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

如何在Java中获取HTTP请求与响应的原始报文?

使用java.net.http捕获HTTP请求与响应原始报文的方案

首先明确:没有完全无需手动编写代码的方式,但有几种简洁的实现方案,不用从头造轮子,下面分别说明:

1. 用JDK内置日志直接打印(几乎零代码修改)

java.net.http本身支持通过日志配置输出原始请求和响应,适合调试场景,不需要改业务代码:

  • 如果用Java Util Logging,在logging.properties里加:
# 打印请求/响应的头部和内容,可选值还有trace、errors等
jdk.httpclient.HttpClient.log=headers,content
  • 如果用Logback等框架,在配置文件里加:
<logger name="jdk.httpclient.HttpClient" level="DEBUG"/>

这种方式的输出是日志形式,要是想把原始报文存成字符串,得自己处理日志内容。

2. 自定义BodyHandler捕获响应原始报文

如果要在代码里直接拿到响应的原始字符串,可以结合TeeInputStream自定义BodyHandler,同时读取响应内容并保存原始报文:

HttpRequest httpsRequest = getHttpsRequest(url, parameters, method, headers);
HttpClient client = HttpClient.newHttpClient();

// 自定义BodyHandler捕获完整响应报文
HttpResponse<String> httpResponse = client.send(httpsRequest, responseInfo -> {
    // 先拼接响应状态行和头部
    StringBuilder rawResponse = new StringBuilder();
    rawResponse.append(responseInfo.version())
            .append(" ")
            .append(responseInfo.statusCode())
            .append(" ")
            .append(responseInfo.reasonPhrase())
            .append("\r\n");
    responseInfo.headers().map().forEach((key, values) -> {
        values.forEach(val -> rawResponse.append(key).append(": ").append(val).append("\r\n"));
    });
    rawResponse.append("\r\n");

    return HttpResponse.BodySubscribers.mapping(
            HttpResponse.BodySubscribers.ofInputStream(),
            inputStream -> {
                try {
                    // 用TeeInputStream同时读取内容并写入字节流,保留原始报文
                    ByteArrayOutputStream baos = new ByteArrayOutputStream();
                    try (TeeInputStream teeStream = new TeeInputStream(inputStream, baos)) {
                        String body = new String(teeStream.readAllBytes(), UTF_8);
                        rawResponse.append(body);
                        return body;
                    } finally {
                        // 这里可以把rawResponse.toString()存到变量或者打印
                        System.out.println("原始响应报文:\n" + rawResponse);
                    }
                } catch (IOException e) {
                    throw new UncheckedIOException(e);
                }
            }
    );
});

3. 用HttpClient Filter同时捕获请求和响应

要是需要同时抓请求和响应的原始报文,可以给HttpClient加Filter:

HttpClient client = HttpClient.newBuilder()
        .filter((request, next) -> {
            // 拼接请求的状态行和头部
            StringBuilder rawRequest = new StringBuilder();
            rawRequest.append(request.method())
                    .append(" ")
                    .append(request.uri())
                    .append(" ")
                    .append(request.version())
                    .append("\r\n");
            request.headers().map().forEach((key, values) -> {
                values.forEach(val -> rawRequest.append(key).append(": ").append(val).append("\r\n"));
            });
            rawRequest.append("\r\n");
            
            // 如果是带请求体的POST/PUT等,需要先缓存请求体(因为流只能读一次)
            // 这里示例简化处理GET请求,POST场景需要额外处理请求体
            System.out.println("原始请求报文:\n" + rawRequest);

            return next.exchange(request).thenApply(response -> {
                // 这里可以结合上面的BodyHandler方式处理响应报文
                return response;
            });
        })
        .build();

HttpRequest httpsRequest = getHttpsRequest(url, parameters, method, headers);
HttpResponse<String> httpResponse = client.send(httpsRequest, HttpResponse.BodyHandlers.ofString(UTF_8));

注意:处理带请求体的请求时,要先把请求体缓存下来,再重新构建请求,因为原始请求体流只能读取一次。

方案选择

  • 调试用优先选日志配置,几乎不用改代码;
  • 要在代码里拿响应报文用自定义BodyHandler+TeeInputStream;
  • 要同时抓请求和响应选HttpClient Filter,注意请求体的流复用问题。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.03 04:15:38