在下面的示例中,我创建了一个 Java 11 httpClient,然后创建了多个并发 HttpRequest。
代码
private static void httpClientExample(){
HttpClient httpClient = HttpClient.newHttpClient();
System.out.println("TP1");
var task1 = httpClient.sendAsync(HttpRequest.newBuilder()
.uri(URI.create("https://www.bing.com/"))
.build(), HttpResponse.BodyHandlers.ofString())
.thenApply(HttpResponse::uri).thenAccept(System.out::println);
var task2 = httpClient.sendAsync(HttpRequest.newBuilder()
.uri(URI.create("https://openjdk.java.net/"))
.build(), HttpResponse.BodyHandlers.ofString())
.thenApply(HttpResponse::uri).thenAccept(System.out::println);
var task3 = httpClient.sendAsync(HttpRequest.newBuilder()
.uri(URI.create("https://www.google.co.uk/"))
.build(), HttpResponse.BodyHandlers.ofString())
.thenApply(HttpResponse::uri).thenAccept(System.out::println);
System.out.println("Requests Sent");
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("Main Thread Completed");
}
Run Code Online (Sandbox Code Playgroud) 我有一个程序,java.net.http.HttpClient它利用 Java 11 中引入的 来连接内部服务并向内部服务发送请求。这些服务相互验证,均提供内部 CA 颁发的证书。
例如,
SSLContext sslContext = SSLContext.getInstance("TLSv1.3");
KeyManager keys = /* load our cert and key */;
TrustManager trust = /* load our trusted CA */;
sslContext.init(keys, trust, secureRandom);
HttpClient.Builder builder = HttpClient.newBuilder().sslContext(sslContext);
HttpClient client = builder.build();
Run Code Online (Sandbox Code Playgroud)
在我们的主机上,客户端的证书和私钥会定期轮换,比主机或应用程序有机会重新启动的频率更高。我希望能够在新的证书/密钥对仍在运行时重新加载它,但看不到任何方法可以做到这一点HttpClient。SSLContext
构建完成后HttpClient,它仅提供一个sslContext()getter 来检索SSLContext. 似乎没有 API 来设置新的。
还有其他机制可以实现这一目标吗?
(我正在考虑类似于 Jetty 的SslContextFactory#reload(SSLContext)方法。)
我是 Java spring 框架的新手,我需要一种从我的应用程序调用外部 Rest API 的方法。是否有任何“最佳实践”http 客户端可以满足我的需要?
JDK11引入了新的HTTP Client,具有许多传统java.net.HttpURLConnection类所缺乏的功能。我遇到的第一个问题是如何在新添加的 HTTP 客户端中正确启用日志记录?
我尝试使用 java 11HttpRequest使用 PATCH 方法调用 msgraph webservice:
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
import java.net.URI;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import groovy.json.JsonSlurper;
import groovy.json.JsonOutput;
access_token = "my_token";
def url = 'https://graph.microsoft.com/v1.0/groups/group_id/drive/items/01P4AIIJ5QTIIAZ2FLEZBIZWRV6KEBIMM5/workbook/worksheets/%7B00000000-0001-0000-0000-000000000000%7D/range(address=\'A1\')'
HttpClient httpClient = HttpClient.newBuilder()
.version(HttpClient.Version.HTTP_2)
.build();
jsonPayloadString = '{"values":["blabla"]}';
jsonPayload = HttpRequest.BodyPublishers.ofString(jsonPayloadString.toString())
HttpRequest request = HttpRequest.newBuilder()
.uri(URI.create(url))
.PATCH(jsonPayload)
.header("Content-Type", "application/json")
.build();
HttpResponse response = httpClient.send(request,HttpResponse.BodyHandlers.ofString());
Run Code Online (Sandbox Code Playgroud)
错误 :
没有方法签名:jdk.internal.net.http.HttpRequestBuilderImpl.PATCH() 适用于参数类型:(jdk.internal.net.http.RequestPublishers$StringPublisher) 值:[jdk.internal.net.http.RequestPublishers$ StringPublisher@280a600b]
通话本身效果很好,例如在 Postman 中。但我不能让它在 groovy/java 中工作。
我以前使用过,HttpUrlConnection但它不支持 PATCH。实际上可以使用HttpRequest吗?
我在网上找不到任何使用 PATCH 方法的工作示例。
在使用java.net.http.HttpClientJava 11 及更高版本中的类时,如何告诉客户端遵循HTTP 303以到达重定向页面?
这是一个例子。维基百科提供了一个 REST URL,用于获取其内容的随机页面的摘要。该 URL 重定向到随机选择的页面的 URL。运行此代码时,我看到303调用HttpResponse#toString. 但我不知道如何告诉客户端类跟随新的 URL。
HttpClient client = HttpClient.newHttpClient();
HttpRequest request =
HttpRequest
.newBuilder()
.uri( URI.create( "https://en.wikipedia.org/api/rest_v1/page/random/summary" ) )
.build();
try
{
HttpResponse < String > response = client.send( request , HttpResponse.BodyHandlers.ofString() );
System.out.println( "response = " + response ); // ?? We can see the `303` status code.
String body = response.body();
System.out.println( "body = " + body );
}
catch ( …Run Code Online (Sandbox Code Playgroud) 我知道HttpClientBuilder您可以使用 Apache调用useSystemProperties(),如果传递为,它将创建一个SSLContext从javax.net.ssl.keyStore(和信任库)配置的客户端JAVA_OPTS:
try (CloseableHttpClient client = HttpClientBuilder.create().useSystemProperties.build()) {
// If javax.net.ssl props are set, make requests that require client auth
// Otherwise make regular requests
}
Run Code Online (Sandbox Code Playgroud)
我想用 Java 11 做一些类似的事情HttpClient。这样做的原因是在我的用例中,我将密钥存储和信任存储视为可选的,并且不必在我的代码中检查它们的存在会很好。基本上,我想SSLContext根据JAVA_OPTS它们是否存在来设置;否则只使用"Default"上下文。
我希望使用java 11 中提供的新 HttpClient。不清楚如何进行双向 TLS(2 路身份验证,客户端和服务器都提供证书。)
有人可以提供一个使用 HttpClient 的双向 TLS 的例子吗?
使用java.net.http.HttpClient以下配置将请求发送到 BitBucket API:
var url = "https://bitbucket.org/api/2.0/repositories/asomov/snakeyaml/issues/377";
HttpClient client = HttpClient.newBuilder()
.followRedirects(HttpClient.Redirect.ALWAYS)
.version(HttpClient.Version.HTTP_2)
.build();
HttpRequest request = HttpRequest.newBuilder()
.GET()
.uri(URI.create(url))
.setHeader("User-Agent", "Java 11 HttpClient Bot")
.timeout(Duration.ofSeconds(5))
.build();
HttpResponse<String> response = client.send(request,
HttpResponse.BodyHandlers.ofString());
Run Code Online (Sandbox Code Playgroud)
总是抛出以下异常:
java.io.IOException: /192.168.1.126:58337: GOAWAY received
at java.net.http/jdk.internal.net.http.HttpClientImpl.send(HttpClientImpl.java:576)
at java.net.http/jdk.internal.net.http.HttpClientFacade.send(HttpClientFacade.java:119)
Caused by: java.io.IOException: /192.168.1.126:58337: GOAWAY received
at java.net.http/jdk.internal.net.http.Http2Connection.handleGoAway(Http2Connection.java:985)
at java.net.http/jdk.internal.net.http.Http2Connection.handleConnectionFrame(Http2Connection.java:853)
at java.net.http/jdk.internal.net.http.Http2Connection.processFrame(Http2Connection.java:724)
at java.net.http/jdk.internal.net.http.frame.FramesDecoder.decode(FramesDecoder.java:155)
at java.net.http/jdk.internal.net.http.Http2Connection$FramesController.processReceivedData(Http2Connection.java:232)
at java.net.http/jdk.internal.net.http.Http2Connection.asyncReceive(Http2Connection.java:649)
at java.net.http/jdk.internal.net.http.Http2Connection$Http2TubeSubscriber.processQueue(Http2Connection.java:1275)
at java.net.http/jdk.internal.net.http.common.SequentialScheduler$SynchronizedRestartableTask.run(SequentialScheduler.java:175)
at java.net.http/jdk.internal.net.http.common.SequentialScheduler$CompleteRestartableTask.run(SequentialScheduler.java:147)
at java.net.http/jdk.internal.net.http.common.SequentialScheduler$SchedulableTask.run(SequentialScheduler.java:198)
at java.net.http/jdk.internal.net.http.common.SequentialScheduler.runOrSchedule(SequentialScheduler.java:271)
at java.net.http/jdk.internal.net.http.common.SequentialScheduler.runOrSchedule(SequentialScheduler.java:224)
at java.net.http/jdk.internal.net.http.Http2Connection$Http2TubeSubscriber.runOrSchedule(Http2Connection.java:1293)
at java.net.http/jdk.internal.net.http.Http2Connection$Http2TubeSubscriber.onNext(Http2Connection.java:1319)
at java.net.http/jdk.internal.net.http.Http2Connection$Http2TubeSubscriber.onNext(Http2Connection.java:1253)
at …Run Code Online (Sandbox Code Playgroud) 上传多个文件时,使用多路复用 http2 功能应该会显着提高性能。
Java 有一个 httpclient,它原生支持 HTTP/2 协议,因此我尝试编写代码以供自己理解。
这项任务似乎并不像我最初想的那样容易,或者在另一方面,我似乎无法找到能够在上传中使用多路复用的服务器(如果存在)。
这是我写的代码,有人有想法吗?
HttpClient httpClient = HttpClient.newBuilder().version(HttpClient.Version.HTTP_2).build();
String url = "https://your-own-http2-server.com/incoming-files/%s";
Path basePath = Path.of("/path/to/directory/where/is/a/bunch/of/jpgs");
Function<Path, CompletableFuture<HttpResponse<String>>> handleFile = file -> {
String currentUrl = String.format(url, file.getFileName().toString());
try {
HttpRequest request = HttpRequest.newBuilder()
.uri(URI.create(currentUrl))
.header("Content-Type", "image/jpeg")
.PUT(HttpRequest.BodyPublishers.ofFile(file))
.build();
return httpClient.sendAsync(request, HttpResponse.BodyHandlers.ofString());
} catch (IOException e) {
e.printStackTrace();
throw new RuntimeException(e);
}
};
List<Path> files = Files.list(basePath).collect(toList());
files.parallelStream().map(handleFile).forEach(c -> {
try {
final HttpResponse<String> response = c.get();
System.out.println(response.statusCode());
} catch (Exception e) {
e.printStackTrace(); …Run Code Online (Sandbox Code Playgroud) 我java.net.http.HttpClient.newHttpClient()在 Java 19 (Temurin) 下使用,并sendAsync(...)在同一实例上执行来自不同步骤的请求。我认为这是可以的,正如 javadoc 所说:
一旦构建,HttpClient 就是不可变的......
但是,某些请求会失败并显示以下信息:
java.io.IOException: HTTP/1.1 header parser received no bytes
Run Code Online (Sandbox Code Playgroud)
奇怪的是,这取决于我的请求的速度:
我为它写了一个测试:
private final HttpRequest request = HttpRequest.newBuilder()
.uri(URI.create("https://..."))
.setHeader("Content-Type", "application/json")
.POST(HttpRequest.BodyPublishers.ofByteArray("[]".getBytes()))
.build();
@ParameterizedTest
@ValueSource(ints = {3, 5})
void httpClientTest(int intervalSeconds) throws Exception {
HttpClient httpClient = HttpClient.newHttpClient();
httpClient.sendAsync(request, HttpResponse.BodyHandlers.ofByteArray()).get();
Thread.sleep(Duration.ofSeconds(intervalSeconds));
httpClient.sendAsync(request, HttpResponse.BodyHandlers.ofByteArray()).get();
Thread.sleep(Duration.ofSeconds(intervalSeconds));
httpClient.sendAsync(request, HttpResponse.BodyHandlers.ofByteArray()).get();
Thread.sleep(Duration.ofSeconds(intervalSeconds));
httpClient.sendAsync(request, HttpResponse.BodyHandlers.ofByteArray()).get();
Thread.sleep(Duration.ofSeconds(intervalSeconds));
httpClient.sendAsync(request, HttpResponse.BodyHandlers.ofByteArray()).get();
}
Run Code Online (Sandbox Code Playgroud)
我已经尝试过以下操作:
curl在命令行上执行相同的操作。无论我尝试什么时间间隔,都没有请求失败。所以应该不是服务器的问题。HttpClient.newHttpClient() …我有一个代码库(显然)可以在下运行,Java 9但不能在下编译Java 11。它使用jdk.incubator.httpclientAPI并根据此答案更改模块信息在大多数情况下都有效,但不仅仅是软件包已更改。
我仍然无法解决的代码如下:
private static JSONObject sendRequest(JSONObject json) throws Exception {
HttpClient client = HttpClient.newHttpClient();
HttpRequest httpRequest = HttpRequest.newBuilder(new URI(BASE_URL))
.header("Accept", "application/json")
.header("Content-Type", "application/json")
.timeout(TIMEOUT_DURATION)
.POST(HttpRequest.BodyProcessor.fromString(json.toString()))
.build();
HttpResponse<String> httpResponse = client.send(httpRequest, HttpResponse.BodyHandler.asString());
String jsonResponse = httpResponse.body();
return new JSONObject(jsonResponse);
}
Run Code Online (Sandbox Code Playgroud)
编译错误为:
Error:(205, 94) java: cannot find symbol
symbol: method asString()
location: interface java.net.http.HttpResponse.BodyHandler
Error:(202, 34) java: cannot find symbol
symbol: variable BodyProcessor
location: class java.net.http.HttpRequest
Run Code Online (Sandbox Code Playgroud)
如何将代码转换为等效Java 11版本?
java-http-client ×12
java ×11
java-11 ×6
ssl ×3
http ×2
bitbucket ×1
file-upload ×1
groovy ×1
http2 ×1
httpclient ×1
httprequest ×1
java-19 ×1
java-9 ×1
json ×1
logging ×1
spring ×1
spring-boot ×1