Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/http/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
当区块到达时,如何使用java.net.HTTP读取和打印区块HTTP响应?_Java_Http_Reactive_Java Http Client - Fatal编程技术网

当区块到达时,如何使用java.net.HTTP读取和打印区块HTTP响应?

当区块到达时,如何使用java.net.HTTP读取和打印区块HTTP响应?,java,http,reactive,java-http-client,Java,Http,Reactive,Java Http Client,Java11引入了一个新的包,Java.net.http,用于发出http请求。对于一般用法,它非常简单 我的问题是:当客户端接收到每个区块时,如何使用java.net.http来处理区块响应 java.http.net包含一个反应式BodySubscriber,这似乎是我想要的,但我找不到如何使用它的示例 http_get_demo.py 下面是一个在块到达时打印块的python实现,我想对java.net.http做同样的事情: import argparse import requests

Java11引入了一个新的包,
Java.net.http
,用于发出http请求。对于一般用法,它非常简单

我的问题是:当客户端接收到每个区块时,如何使用
java.net.http
来处理区块响应

java.http.net
包含一个反应式
BodySubscriber
,这似乎是我想要的,但我找不到如何使用它的示例

http_get_demo.py 下面是一个在块到达时打印块的python实现,我想对java.net.http做同样的事情:

import argparse
import requests


def main(url: str):
    with requests.get(url, stream=True) as r:
        for c in r.iter_content(chunk_size=1):
            print(c.decode("UTF-8"), end="")


if __name__ == "__main__":
    parser = argparse.ArgumentParser(
        description="Read from a URL and print as text as chunks arrive")
    parser.add_argument('url', type=str, help="A URL to read from")
    args = parser.parse_args()

    main(args.url)
import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpResponse;
import java.net.http.HttpRequest;

public class HttpGetDemo {

  public static void main(String[] args) throws Exception {

    var request = HttpRequest.newBuilder()
            .uri(URI.create(args[0]))
            .build();

    var bodyHandler = HttpResponse.BodyHandlers
            .ofString();

    var client = HttpClient.newHttpClient();
    var response = client.send(request, bodyHandler);
    System.out.println(response.body());

  }
}
HttpGetDemo.java 为了完整起见,下面是一个使用java.net.http发出阻塞请求的简单示例:

import argparse
import requests


def main(url: str):
    with requests.get(url, stream=True) as r:
        for c in r.iter_content(chunk_size=1):
            print(c.decode("UTF-8"), end="")


if __name__ == "__main__":
    parser = argparse.ArgumentParser(
        description="Read from a URL and print as text as chunks arrive")
    parser.add_argument('url', type=str, help="A URL to read from")
    args = parser.parse_args()

    main(args.url)
import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpResponse;
import java.net.http.HttpRequest;

public class HttpGetDemo {

  public static void main(String[] args) throws Exception {

    var request = HttpRequest.newBuilder()
            .uri(URI.create(args[0]))
            .build();

    var bodyHandler = HttpResponse.BodyHandlers
            .ofString();

    var client = HttpClient.newHttpClient();
    var response = client.send(request, bodyHandler);
    System.out.println(response.body());

  }
}
HttpAsyncGetDemo.java 下面是生成非阻塞/异步请求的示例:

import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpResponse;
import java.net.http.HttpRequest;

/**
 * ReadChunked
 */
public class HttpAsyncGetDemo {

  public static void main(String[] args) throws Exception {

    var request = HttpRequest.newBuilder()
            .uri(URI.create(args[0]))
            .build();

    var bodyHandler = HttpResponse.BodyHandlers
            .ofString();

    var client = HttpClient.newHttpClient();

    client.sendAsync(request, bodyHandler)
            .thenApply(HttpResponse::body)
            .thenAccept(System.out::println)
            .join();

  }
}

您可以按原样打印
ByteBuffer
s,但不能保证
ByteBuffer
对应于块。块由堆栈处理。将为每个块推送一个
ByteBuffer
切片-但是如果缓冲区中没有足够的剩余空间,则将推送部分块。消费者看到的只是包含数据的
ByteBuffer
s流。 因此,您可以做的是打印这些
ByteBuffer
s,但您不能保证它们与服务器发送的每个块完全对应

注意:如果请求的正文是基于文本的,那么您可以使用
BodyHandlers.fromLineSubscriber(订阅方您可以打印
ByteBuffer
s,但不能保证
ByteBuffer
对应一个块。块由堆栈处理。每个块将推送一个
ByteBuffer
片,但如果缓冲区中没有足够的空间,则会推送部分块。所有e consumer sees是一个包含数据的
字节缓冲流。
因此,您可以做的是打印这些
ByteBuffer
s,但您不能保证它们与服务器发送的每个块完全对应

注意:如果请求的正文是基于文本的,那么您可以使用
BodyHandlers.fromLineSubscriber(Subscriberpython代码不确保每次提供一个响应主体数据。它只向应用程序提供少量数据,从而减少了应用程序级消耗的内存量(可以在堆栈中的较低位置缓冲).Java 11 HTTP客户端支持通过流式正文处理程序之一进行流式处理,
HttpResponse.BodyHandler
of InputStream
of ByteArrayConsumer
asLines

或者编写自己的处理程序/订阅服务器,如所示:

python代码不能确保响应主体数据一次一个可用。它只向应用程序提供少量数据,从而减少应用程序级消耗的内存量(可以在堆栈中的较低位置缓冲).Java 11 HTTP客户端支持通过流式正文处理程序之一进行流式处理,
HttpResponse.BodyHandler
of InputStream
of ByteArrayConsumer
asLines

或者编写自己的处理程序/订阅服务器,如所示:
感谢@pavel和@chegar999的部分回答。他们引导我找到了我的解决方案

概述 我提出的解决方案如下。基本上,解决方案是使用自定义
java.net.http.HttpResponse.BodySubscriber
。BodySubscriber包含被动方法(onSubscribe、onNext、onError和onComplete)还有一个getBody方法,它基本上返回一个java,最终将生成HTTP请求的主体

HttpClient client = HttpClient.newHttpClient();
HttpRequest request = HttpRequest.newBuilder()
    .uri(URI.create(uri))
    .build();

return client.sendAsync(request, responseInfo -> new StringSubscriber())
    .whenComplete((r, t) -> System.out.println("--- Status code " + r.statusCode()))
    .thenApply(HttpResponse::body);
请注意这一行:

client.sendsync(请求、响应信息->新建StringSubscriber())

这就是我们注册自定义BodySubscriber的地方;在本例中,我的自定义类名为
StringSubscriber

CustomSubscriber.java 这是一个完整的工作示例。使用Java 11,您可以运行它,而无需编译它。只需将它放入名为
CustomSubscriber.Java
的文件中,然后运行命令
Java CustomSubscriber
。它会在到达时打印每个块的内容。它还会收集它们,并在响应完成后将它们作为正文返回d

import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
import java.net.http.HttpResponse.BodyHandlers;
import java.net.http.HttpResponse.BodySubscriber;
import java.net.URI;
import java.nio.ByteBuffer;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.CompletionStage;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.concurrent.Flow;
import java.util.stream.Collectors;
import java.util.List;

public class CustomSubscriber {

  public static void main(String[] args) {
    CustomSubscriber cs = new CustomSubscriber();
    String body = cs.get(args[0]).join();
    System.out.println("--- Response body:\n: ..." + body + "...");
  }

  public CompletableFuture<String> get(String uri) {
    HttpClient client = HttpClient.newHttpClient();
    HttpRequest request = HttpRequest.newBuilder()
        .uri(URI.create(uri))
        .build();

    return client.sendAsync(request, responseInfo -> new StringSubscriber())
        .whenComplete((r, t) -> System.out.println("--- Status code " + r.statusCode()))
        .thenApply(HttpResponse::body);
  }

  static class StringSubscriber implements BodySubscriber<String> {

    final CompletableFuture<String> bodyCF = new CompletableFuture<>();
    Flow.Subscription subscription;
    List<ByteBuffer> responseData = new CopyOnWriteArrayList<>();

    @Override
    public CompletionStage<String> getBody() {
      return bodyCF;
    }

    @Override
    public void onSubscribe(Flow.Subscription subscription) {
      this.subscription = subscription;
      subscription.request(1); // Request first item
    }

    @Override
    public void onNext(List<ByteBuffer> buffers) {
      System.out.println("-- onNext " + buffers);
      try {
        System.out.println("\tBuffer Content:\n" + asString(buffers));
      } 
      catch (Exception e) {
        System.out.println("\tUnable to print buffer content");
      }
      buffers.forEach(ByteBuffer::rewind); // Rewind after reading
      responseData.addAll(buffers);
      subscription.request(1); // Request next item
    }

    @Override
    public void onError(Throwable throwable) {
      bodyCF.completeExceptionally(throwable);
    }

    @Override
    public void onComplete() {
      bodyCF.complete(asString(responseData));
    }

    private String asString(List<ByteBuffer> buffers) {
      return new String(toBytes(buffers), StandardCharsets.UTF_8);
    }

    private byte[] toBytes(List<ByteBuffer> buffers) {
      int size = buffers.stream()
          .mapToInt(ByteBuffer::remaining)
          .sum();
      byte[] bs = new byte[size];
      int offset = 0;
      for (ByteBuffer buffer : buffers) {
        int remaining = buffer.remaining();
        buffer.get(bs, offset, remaining);
        offset += remaining;
      }
      return bs;
    }

  }
}
导入java.net.http.HttpClient;
导入java.net.http.HttpRequest;
导入java.net.http.HttpResponse;
导入java.net.http.HttpResponse.bodyHandler;
导入java.net.http.HttpResponse.BodySubscriber;
导入java.net.URI;
导入java.nio.ByteBuffer;
导入java.nio.charset.StandardCharset;
导入java.util.ArrayList;
导入java.util.concurrent.CompletableFuture;
导入java.util.concurrent.CompletionStage;
导入java.util.concurrent.CopyOnWriteArrayList;
导入java.util.concurrent.Flow;
导入java.util.stream.collector;
导入java.util.List;
公共类自定义订户{
公共静态void main(字符串[]args){
CustomSubscriber cs=新CustomSubscriber();
字符串体=cs.get(args[0]).join();
System.out.println(“--Response body:\n:…”+body+”);
}
公共CompletableFuture get(字符串uri){
HttpClient=HttpClient.newHttpClient();
HttpRequest请求=HttpRequest.newBuilder()
.uri(uri.create(uri))
.build();
返回client.sendsync(请求、响应信息->新建StringSubscriber())
.whenComplete((r,t)->System.out.println(“--Status code”+r.statusCode()))
.然后应用(HttpResponse::body);
}
静态类StringSubscriber实现BodySubscriber{
最终CompletableFuture正文cf=新的CompletableFuture();
流动。认购;
List responseData=new CopyOnWriteArrayList();
@凌驾
public CompletionStage getBody(){