如何获取所有有效的HTTP请求headers?

How to get all effective HTTP request headers?

我想使用新的 java.net.HttpClient 向另一个系统发送一些请求。

出于调试目的,我想记录(并稍后存储在我们的数据库中)我发送的请求和我收到的响应。

如何检索 java 正在发送的 有效 http headers?

我试过这样得到 headers:

HttpRequest request = HttpRequest.newBuilder()
        .uri(URI.create("http://localhost:54113"))
        .build();

System.out.println("HTTP-Headers:\n---");
request.headers().map()
        .forEach((key, values) ->
                values.forEach(value ->
                        System.out.println(key + ": " + value)
                )
        );
System.out.println("---");

HttpClient.newHttpClient().send(request, HttpResponse.BodyHandlers.ofString());

但它输出:

HTTP-Headers:
---
---

然而,我的服务器告诉我,它收到了这些 Http headers:

HTTP-Headers:
---
Connection: Upgrade, HTTP2-Settings
User-Agent: Java-http-client/11
Host: localhost:54113
HTTP2-Settings: AAEAAEAAAAIAAAABAAMAAABkAAQBAAAAAAUAAEAA
Content-Length: 0
Upgrade: h2c
---

我有一个多线程应用程序,可能会出现同时请求。因此,使用带有自定义附加程序的日志框架可能不可靠。

我对你的问题有一个不幸的答案:很遗憾,不可能

为什么会出现这种情况的一些背景知识:

您的平均 OpenJDK-based java-core-library 实现使用的 HttpRequest 的实际实现是 而不是 java.net.http.HttpRequest - 这只是一个接口。这是 jdk.internal.net.http.HttpRequestImpl.

此代码有 2 个单独的 headers 列表要发送;一个是 'user headers',另一个是 'system headers'。您的 .headers() 调用仅检索用户 headers,这是您明确要求发送的 headers,当然,当您要求 none 发送时,它是空的。

系统 headers 是这 6 个 headers 的来源。我认为没有办法以受支持的方式获得这些。不幸的是,如果你想深入研究不受支持的策略(你编写查询内部状态的代码,因此不能保证在其他 JVM 实现或基本 JVM 实现的未来版本上工作),它仍然非常困难!一些基本的反思不会在这里完成工作。这是可以想象到的最糟糕的消息:

  • 这 6 个 headers 根本没有设置,直到 send 被调用。比如在package-privatesetH2Upgrade方法中设置了HTTP2相关的三个headers,而这个方法又传给了HttpClientobject,证明这不可能在您调用 send 时开始的事件链中调用除外。 HttpClient object 不存在于生成 HttpRequest object 的代码链中,这证明了这一点。

  • 更糟糕的是,默认的 HttpClient impl 将首先克隆你的 HttpRequest,然后在这个克隆上做一堆操作(包括添加那些系统 headers),然后发送克隆,这意味着您拥有的 HttpRequest object 没有任何这些 headers。甚至 after 发送调用完成。因此,即使您可以在发送 之后获取这些 headers 并且可以使用反射来挖掘内部状态以获取 em,它也行不通。

您也无法反映到客户端,因为相关状态(您的 httprequest object 的克隆)不在字段中,它在局部变量中,反射无法获取您那些。

HttpRequest 可以配置自定义代理,这也不是一个很好的解决方案:那是 TCP/IP 级代理,而不是 HTTP 代理,并且 headers 使用 HTTPS 加密发送。因此,编写(ab)使用代理设置的代码,以便您可以创建一个 'proxy',它在发送之前首先围绕您自己的代码反弹连接,以便查看传输中的 headers , 绝对是 non-trivial.

我能为您提供的唯一解决方案是完全放弃 java.net.http.HttpClient 并使用可以满足您需求的 non-java-lib-core 库。也许 OkHttp。 (在你唱哈利路亚之前,我实际上并不知道 OkHttp 是否可以为你提供它打算发送的所有 headers,或者给你一个方法来注册一个被及时通知的钩子,所以先调查一下!)