标签: java-http-client

如何使用Java HttpClient库上传文件

我想编写Java应用程序,用PHP将文件上传到Apache服务器.Java代码使用Jakarta HttpClient库版本4.0 beta2:

import java.io.File;
import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.HttpVersion;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.FileEntity;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.params.CoreProtocolPNames;
import org.apache.http.util.EntityUtils;


public class PostFile {
  public static void main(String[] args) throws Exception {
    HttpClient httpclient = new DefaultHttpClient();
    httpclient.getParams().setParameter(CoreProtocolPNames.PROTOCOL_VERSION, HttpVersion.HTTP_1_1);

    HttpPost httppost = new HttpPost("http://localhost:9002/upload.php");
    File file = new File("c:/TRASH/zaba_1.jpg");

    FileEntity reqEntity = new FileEntity(file, "binary/octet-stream");

    httppost.setEntity(reqEntity);
    reqEntity.setContentType("binary/octet-stream");
    System.out.println("executing request " + httppost.getRequestLine());
    HttpResponse response = httpclient.execute(httppost);
    HttpEntity resEntity = response.getEntity();

    System.out.println(response.getStatusLine());
    if (resEntity != null) {
      System.out.println(EntityUtils.toString(resEntity)); …
Run Code Online (Sandbox Code Playgroud)

php java java-http-client

51
推荐指数
2
解决办法
12万
查看次数

Java 21内置HTTP客户端固定载体线程

我正在使用 Java Corretto 21.0.0.35.1 build 21+35-LTS和内置 Java HTTP 客户端来检索InputStream. 我正在使用虚拟线程发出并行请求,并且在大多数情况下,它运行良好。然而,有时,我的测试会遇到“固定”事件,如下面的堆栈跟踪所示。

我相信 JDK 已经更新为完全支持虚拟线程,并且根据我的理解,HTTP 客户端根本不应该固定承载线程。但是,似乎在读取并(自动)关闭InputStream.

这是预期的行为吗?或者它仍然是 JDK 中的一个错误吗?

代码:

HttpResponse<InputStream> response = httpClient.send(request, HttpResponse.BodyHandlers.ofInputStream());
try (InputStream responseBody = response.body()) {
  return parser.parse(responseBody); // LINE 52 in the trace below
}
Run Code Online (Sandbox Code Playgroud)

踪迹

* Pinning event captured:
  java.lang.VirtualThread.parkOnCarrierThread(java.lang.VirtualThread.java:687)
  java.lang.VirtualThread.park(java.lang.VirtualThread.java:603)
  java.lang.System$2.parkVirtualThread(java.lang.System$2.java:2639)
  jdk.internal.misc.VirtualThreads.park(jdk.internal.misc.VirtualThreads.java:54)
  java.util.concurrent.locks.LockSupport.park(java.util.concurrent.locks.LockSupport.java:219)
  java.util.concurrent.locks.AbstractQueuedSynchronizer.acquire(java.util.concurrent.locks.AbstractQueuedSynchronizer.java:754)
  java.util.concurrent.locks.AbstractQueuedSynchronizer.acquire(java.util.concurrent.locks.AbstractQueuedSynchronizer.java:990)
  java.util.concurrent.locks.ReentrantLock$Sync.lock(java.util.concurrent.locks.ReentrantLock$Sync.java:153)
  java.util.concurrent.locks.ReentrantLock.lock(java.util.concurrent.locks.ReentrantLock.java:322)
  sun.nio.ch.SocketChannelImpl.implCloseNonBlockingMode(sun.nio.ch.SocketChannelImpl.java:1091)
  sun.nio.ch.SocketChannelImpl.implCloseSelectableChannel(sun.nio.ch.SocketChannelImpl.java:1124)
  java.nio.channels.spi.AbstractSelectableChannel.implCloseChannel(java.nio.channels.spi.AbstractSelectableChannel.java:258)
  java.nio.channels.spi.AbstractInterruptibleChannel.close(java.nio.channels.spi.AbstractInterruptibleChannel.java:113)
  jdk.internal.net.http.PlainHttpConnection.close(jdk.internal.net.http.PlainHttpConnection.java:427)
  jdk.internal.net.http.PlainHttpConnection.close(jdk.internal.net.http.PlainHttpConnection.java:406)
  jdk.internal.net.http.Http1Response.lambda$readBody$1(jdk.internal.net.http.Http1Response.java:355)
  jdk.internal.net.http.Http1Response$$Lambda+0x00007f4cb5e6c438.749276779.accept(jdk.internal.net.http.Http1Response$$Lambda+0x00007f4cb5e6c438.749276779.java:-1)
  jdk.internal.net.http.ResponseContent$ChunkedBodyParser.onError(jdk.internal.net.http.ResponseContent$ChunkedBodyParser.java:185)
  jdk.internal.net.http.Http1Response$BodyReader.onReadError(jdk.internal.net.http.Http1Response$BodyReader.java:677)
  jdk.internal.net.http.Http1AsyncReceiver.checkForErrors(jdk.internal.net.http.Http1AsyncReceiver.java:302)
  jdk.internal.net.http.Http1AsyncReceiver.flush(jdk.internal.net.http.Http1AsyncReceiver.java:268)
  jdk.internal.net.http.Http1AsyncReceiver$$Lambda+0x00007f4cb5e31228.555093431.run(jdk.internal.net.http.Http1AsyncReceiver$$Lambda+0x00007f4cb5e31228.555093431.java:-1)
  jdk.internal.net.http.common.SequentialScheduler$LockingRestartableTask.run(jdk.internal.net.http.common.SequentialScheduler$LockingRestartableTask.java:182)
  jdk.internal.net.http.common.SequentialScheduler$CompleteRestartableTask.run(jdk.internal.net.http.common.SequentialScheduler$CompleteRestartableTask.java:149)
  jdk.internal.net.http.common.SequentialScheduler$SchedulableTask.run(jdk.internal.net.http.common.SequentialScheduler$SchedulableTask.java:207)
  jdk.internal.net.http.HttpClientImpl$DelegatingExecutor.execute(jdk.internal.net.http.HttpClientImpl$DelegatingExecutor.java:177)
  jdk.internal.net.http.common.SequentialScheduler.runOrSchedule(jdk.internal.net.http.common.SequentialScheduler.java:282)
  jdk.internal.net.http.common.SequentialScheduler.runOrSchedule(jdk.internal.net.http.common.SequentialScheduler.java:251)
  jdk.internal.net.http.Http1AsyncReceiver.onReadError(jdk.internal.net.http.Http1AsyncReceiver.java:516)
  jdk.internal.net.http.Http1AsyncReceiver.lambda$handlePendingDelegate$3(jdk.internal.net.http.Http1AsyncReceiver.java:380)
  jdk.internal.net.http.Http1AsyncReceiver$$Lambda+0x00007f4cb5e33ca0.84679411.run(jdk.internal.net.http.Http1AsyncReceiver$$Lambda+0x00007f4cb5e33ca0.84679411.java:-1) …
Run Code Online (Sandbox Code Playgroud)

java java-http-client project-loom virtual-threads java-21

19
推荐指数
1
解决办法
2406
查看次数

允许Java JDK 11 HttpClient的不安全的HTTPS连接

有时需要允许不安全的HTTPS连接,例如在一些应该与任何站点一起使用的Web爬行应用程序中.我在旧的HttpsURLConnection API中使用了一个这样的解决方案,最近被JDK 11中的新HttpClient API取代了.使用这个新API允许不安全的HTTPS连接(自签名或过期证书)的方法是什么?

UPD:我尝试的代码(在Kotlin中,但直接映射到Java):

    val trustAllCerts = arrayOf<TrustManager>(object: X509TrustManager {
        override fun getAcceptedIssuers(): Array<X509Certificate>? = null
        override fun checkClientTrusted(certs: Array<X509Certificate>, authType: String) {}
        override fun checkServerTrusted(certs: Array<X509Certificate>, authType: String) {}
    })

    val sslContext = SSLContext.getInstance("SSL")
    sslContext.init(null, trustAllCerts, SecureRandom())

    val sslParams = SSLParameters()
    // This should prevent host validation
    sslParams.endpointIdentificationAlgorithm = ""

    httpClient = HttpClient.newBuilder()
        .sslContext(sslContext)
        .sslParameters(sslParams)
        .build()
Run Code Online (Sandbox Code Playgroud)

但在发送时我有异常(尝试使用自签名证书的localhost):

java.io.IOException: No name matching localhost found
Run Code Online (Sandbox Code Playgroud)

使用IP地址而不是localhost会出现"无主题替代名称存在"异常.

在对JDK进行一些调试之后,我发现sslParams在抛出异常的地方真的被忽略了,并且使用了一些本地创建的实例.进一步调试显示,影响主机名验证算法的唯一方法是将jdk.internal.httpclient.disableHostnameVerification系统属性设置为true.这似乎是一个解决方案.SSLParameters在上面的代码中没有任何影响,所以这部分可以被丢弃.使其仅在全局配置看起来像新的HttpClient API中的严重设计缺陷.

java java-http-client java-11

14
推荐指数
3
解决办法
3993
查看次数

在URL查询参数中使用某些字符时出现Java 9 HttpClient异常

这是我的示例代码.查询编码为UTF-8:

HttpRequest request = HttpRequest.newBuilder()
    .header("content-type", "application/json;charset=UTF-8")
    .uri(URI.create("http://localhost:8080/test?param1=test%C5%84"))
    .GET()
    .build();

HttpClient.newBuilder()
    .version(HttpClient.Version.HTTP_2)
    .build()
    .send(request, HttpResponse.BodyHandler.asString(Charset.forName("UTF-8")));
Run Code Online (Sandbox Code Playgroud)

运行此示例后,我得到以下异常:

java.lang.IllegalArgumentException: char=324
at jdk.incubator.httpclient/jdk.incubator.http.internal.hpack.Huffman.codeOf(Huffman.java:559)
at jdk.incubator.httpclient/jdk.incubator.http.internal.hpack.Huffman.lengthOf(Huffman.java:524)
at jdk.incubator.httpclient/jdk.incubator.http.internal.hpack.StringWriter.configure(StringWriter.java:79)
at jdk.incubator.httpclient/jdk.incubator.http.internal.hpack.StringWriter.configure(StringWriter.java:62)
at jdk.incubator.httpclient/jdk.incubator.http.internal.hpack.IndexNameValueWriter.value(IndexNameValueWriter.java:64)
at jdk.incubator.httpclient/jdk.incubator.http.internal.hpack.Encoder.literal(Encoder.java:422)
at jdk.incubator.httpclient/jdk.incubator.http.internal.hpack.Encoder.header(Encoder.java:245)
at jdk.incubator.httpclient/jdk.incubator.http.internal.hpack.Encoder.header(Encoder.java:198)
at jdk.incubator.httpclient/jdk.incubator.http.Http2Connection.encodeHeadersImpl(Http2Connection.java:927)
at jdk.incubator.httpclient/jdk.incubator.http.Http2Connection.encodeHeaders(Http2Connection.java:878)
at jdk.incubator.httpclient/jdk.incubator.http.Http2Connection.encodeHeaders(Http2Connection.java:951)
at jdk.incubator.httpclient/jdk.incubator.http.Http2Connection.sendFrame(Http2Connection.java:984)
at jdk.incubator.httpclient/jdk.incubator.http.Stream.sendHeadersAsync(Stream.java:547)
at jdk.incubator.httpclient/jdk.incubator.http.Exchange.lambda$responseAsyncImpl0$8(Exchange.java:322)
at java.base/java.util.concurrent.CompletableFuture$UniCompose.tryFire(CompletableFuture.java:1072)
at java.base/java.util.concurrent.CompletableFuture.postComplete(CompletableFuture.java:506)
at java.base/java.util.concurrent.CompletableFuture.complete(CompletableFuture.java:2073)
at jdk.incubator.httpclient/jdk.incubator.http.internal.common.SSLFlowDelegate.setALPN(SSLFlowDelegate.java:164)
at jdk.incubator.httpclient/jdk.incubator.http.internal.common.SSLFlowDelegate.access$200(SSLFlowDelegate.java:81)
at jdk.incubator.httpclient/jdk.incubator.http.internal.common.SSLFlowDelegate$Reader.processData(SSLFlowDelegate.java:340)
at jdk.incubator.httpclient/jdk.incubator.http.internal.common.SSLFlowDelegate$Reader$ReaderDownstreamPusher.run(SSLFlowDelegate.java:215)
at jdk.incubator.httpclient/jdk.incubator.http.internal.common.SequentialScheduler$SynchronizedRestartableTask.run(SequentialScheduler.java:175)
at jdk.incubator.httpclient/jdk.incubator.http.internal.common.SequentialScheduler$CompleteRestartableTask.run(SequentialScheduler.java:147)
at jdk.incubator.httpclient/jdk.incubator.http.internal.common.SequentialScheduler$TryEndDeferredCompleter.complete(SequentialScheduler.java:315)
at jdk.incubator.httpclient/jdk.incubator.http.internal.common.SequentialScheduler$CompleteRestartableTask.run(SequentialScheduler.java:149)
at jdk.incubator.httpclient/jdk.incubator.http.internal.common.SequentialScheduler$SchedulableTask.run(SequentialScheduler.java:198)
at jdk.incubator.httpclient/jdk.incubator.http.internal.common.SequentialScheduler.runOrSchedule(SequentialScheduler.java:271)
at jdk.incubator.httpclient/jdk.incubator.http.internal.common.SequentialScheduler.runOrSchedule(SequentialScheduler.java:224)
at jdk.incubator.httpclient/jdk.incubator.http.internal.common.SSLFlowDelegate$Reader.incoming(SSLFlowDelegate.java:242)
at jdk.incubator.httpclient/jdk.incubator.http.internal.common.SubscriberWrapper.incomingCaller(SubscriberWrapper.java:388)
at jdk.incubator.httpclient/jdk.incubator.http.internal.common.SubscriberWrapper.onNext(SubscriberWrapper.java:343) …
Run Code Online (Sandbox Code Playgroud)

java url-encoding http2 java-9 java-http-client

13
推荐指数
1
解决办法
228
查看次数

带有sendAsyncMulti/multiResponseAsync的Java 9 HttpClient

我正在尝试使用Java 9 HttpClient.

HttpRequest的javadoc中的基本示例可以正常工作:

HttpResponse response = HttpRequest.create(new URI("http://stackoverflow.com/"))
       .version(java.net.http.HttpClient.Version.HTTP_2)
       .followRedirects(HttpClient.Redirect.ALWAYS)
       .GET()
       .response();

       int statusCode = response.statusCode();
       String responseBody = response.body(HttpResponse.asString());

       System.out.println("statusCode = " + statusCode);
       System.out.println("responseBody = " + responseBody);
Run Code Online (Sandbox Code Playgroud)

但是,在尝试使用时sendAsyncMulti,它不起作用.没有创建文件E:\foo,未达到printlnafter join,也没有异常,虽然我基本上是从HttpResponse.multiFileJavadoc复制了这个例子.我希望一些HTTP响应将保存在该目录中.我还试图删除HTTP2和followRedirects,谷歌等其他URL,但它没有改变任何东西.我究竟做错了什么?

CompletableFuture<Map<URI,Path>> cf =
    HttpRequest.create(new URI("http://stackoverflow.com/"))
        .version(java.net.http.HttpClient.Version.HTTP_2)
        .followRedirects(HttpClient.Redirect.ALWAYS)
        .GET()
        .multiResponseAsync(HttpResponse.multiFile(Paths.get("E:\\foo")));
Map<URI,Path> results = cf.join();
System.out.println("after join");
Run Code Online (Sandbox Code Playgroud)

如果它是相关的,这是我使用的版本(JDK 9的最新版本):

java version "9-ea"
Java(TM) SE Runtime Environment (build 9-ea+126)
Java HotSpot(TM) Server VM (build 9-ea+126, mixed mode)
Run Code Online (Sandbox Code Playgroud)

java java-9 java-http-client

12
推荐指数
1
解决办法
674
查看次数

使用 Java 11 HttpClient 和带有 Jackson 的自定义 BodyHandler 反序列化 JSON 停止并且不会继续

我在使用HttpClient::send带有 custom 的Java 11 直接将 JSON 反序列化为自定义对象时遇到问题HttpResponse.BodyHandler。我在回答这个 SO question时遇到了这个问题

我使用的版本:

  • OpenJDK 11
  • 杰克逊 2.9.9.3

我创建了一个简单的泛型JsonBodyHandler类,它实现HttpResponse.BodyHandler

public class JsonBodyHandler<W> implements HttpResponse.BodyHandler<W> {

    private final Class<W> wClass;

    public JsonBodyHandler(Class<W> wClass) {
        this.wClass = wClass;
    }

    @Override
    public HttpResponse.BodySubscriber<W> apply(HttpResponse.ResponseInfo responseInfo) {
        return asJSON(wClass);
    }

}
Run Code Online (Sandbox Code Playgroud)

asJSON方法定义为:

public static <W> HttpResponse.BodySubscriber<W> asJSON(Class<W> targetType) {
        HttpResponse.BodySubscriber<String> upstream = HttpResponse.BodySubscribers.ofString(StandardCharsets.UTF_8);

        return HttpResponse.BodySubscribers.mapping(
                upstream,
                (String body) -> {
                    try {
                        ObjectMapper objectMapper …
Run Code Online (Sandbox Code Playgroud)

java jackson java-http-client java-11

12
推荐指数
2
解决办法
8964
查看次数

重试 HTTP 请求(Java 11 - HttpClient)

问题

使用HttpClientJava 11(JDK,而不是 Apache),如何重试请求?

假设我想重试一个请求最多10 次,如果它没有返回状态代码200抛出异常。


试图

目前,我正在循环中重新安排返回的未来,我想知道是否有更好或更优雅的方式。

CompletableFuture<HttpResponse<Foo>> task = client.sendAsync(request, bodyHandler);

for (int i = 0; i < 10; i++) {
    task = task.thenComposeAsync(response -> response.statusCode() == 200 ?
        CompletableFuture.completedFuture(response) :
        client.sendAsync(request, bodyHandler));
}

// Do something with 'task' ...
Run Code Online (Sandbox Code Playgroud)

如果我们也为特殊情况添加重试,我最终会得到

CompletableFuture<HttpResponse<Foo>> task = client.sendAsync(request, bodyHandler);

for (int i = 0; i < 10; i++) {
    task = task.thenComposeAsync(response ->
            response.statusCode() == 200 ?
            CompletableFuture.completedFuture(response) :
            client.sendAsync(request, bodyHandler))
        .exceptionallyComposeAsync(e -> …
Run Code Online (Sandbox Code Playgroud)

java http request retry-logic java-http-client

12
推荐指数
1
解决办法
2万
查看次数

Java 9没有类定义异常

所以我想尝试http客户端

package com.company;

import jdk.incubator.http.HttpClient;

public class Main {

public static void main(String[] args) {
    HttpClient client =  HttpClient.newHttpClient();

  }
}
Run Code Online (Sandbox Code Playgroud)

我的模块信息看起来像这样

module com.company {
    requires jdk.incubator.httpclient;
}
Run Code Online (Sandbox Code Playgroud)

但我明白了 java.lang.NoClassDefFoundError: jdk/incubator/http/HttpClient

我真的不明白为什么.我的java版本是"build 9-ea + 169",我使用最新版本的IntelliJ idea(2017.1.3).我查看了这个答案,看起来我只需要将需求添加到文件中,但由于某种原因它不起作用.

java java-9 java-http-client

11
推荐指数
2
解决办法
2726
查看次数

如何使用 HttpClient 处理 HTTP/2 GOAWAY?

我试图每隔几分钟不断地向 REST API 发送 GET 和 POST 请求。问题是,在恰好 1000 个请求之后,我收到了一个GOAWAY帧(和一个IOException):

GOAWAY 帧(类型=0x7)用于启动连接关闭或发出严重错误情况的信号。
HTTP/2 规范


我做了一些研究,发现 1000 个请求不仅是nginx 的默认最大值,Cloudfront(相关的 Chromium 问题)和 Discord 也表现出相同的行为。

我尝试使用具有默认 HTTP/2 配置的本地 nginx 服务器重现此问题:

服务器 {
    听 443 http2 ssl;
    http2_max_requests 1000;
    ...
}
var client = HttpClient.newBuilder()
        .version(HttpClient.Version.HTTP_2)
        .build();

for (var i = 0; i < 1100; i++) {
    var url = URI.create(String.format("https://localhost/images/test%d.jpg", i));

    var request = HttpRequest.newBuilder().uri(url).build();

    client.send(request, HttpResponse.BodyHandlers.discarding());
    System.out.printf("Image %d processed%n", i);
}
Run Code Online (Sandbox Code Playgroud)

在大约 1000 个请求之后,我收到了 …

java http2 java-http-client java-11

10
推荐指数
1
解决办法
6843
查看次数

关闭Java HTTP客户端

有没有办法java.net.http.HttpClient立即释放它所持有的资源?

在内部,它包含一个选择器,一个连接池和一个Executor(当使用默认值时).但它没有实现Closeable/ AutoCloseable.

java java-http-client java-11

9
推荐指数
2
解决办法
967
查看次数