La cancelación de la solicitud HTTP en Java 11 HttpClient

Kirill Chaykin:

Estoy intentando cancelar http nueva solicitud a través de Java 11 HttpClient.

Este es mi código de prueba:

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

public class App {

    public static void main(String... args) throws InterruptedException {
        HttpClient client = HttpClient.newBuilder().build();

        URI uri = URI.create("http://releases.ubuntu.com/18.04.2/ubuntu-18.04.2-desktop-amd64.iso");
        HttpRequest request = HttpRequest.newBuilder().uri(uri).GET().build();

        var bodyHandler = HttpResponse.BodyHandlers.ofByteArrayConsumer(b -> System.out.println("#"));
        var future = client.sendAsync(request, bodyHandler);
        Thread.sleep(1000);

        future.cancel(true);
        System.out.println("\r\n----------CANCEL!!!------------");
        System.out.println("\r\nisCancelled: " + future.isCancelled());
        Thread.sleep(250);
    }
}

Espero, que la tarea solicitud será cancelada inmediatamente después de future.cancel(true);la línea invoca. Y, por lo tanto, la última línea impresa en la consola debe estarisCancelled: true

Sin embargo, cuando ejecuta este código, veo algo como esto:

################################################## ################################################## 
---------- ------------ CANCELAR !!! 
#### 
isCancelled: verdadera 
################# ################################################## ################################################## ##################################

Esto significa que las solicitudes de tarea aún en marcha después de que la cancele ... Así, que es el camino correcto para cancelar la solicitud?

UPD

Manera correcta de solicitud de cancelación es (como Daniel sugirió, + UPD2: evitar NPE en cancel()método invoke):

import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
import java.net.http.HttpResponse.BodyHandler;
import java.net.http.HttpResponse.BodySubscriber;
import java.net.http.HttpResponse.ResponseInfo;
import java.nio.ByteBuffer;
import java.util.List;
import java.util.concurrent.CompletionStage;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Flow.Subscription;

public class App {

    private static class SubscriberWrapper implements BodySubscriber<Void> {
        private final CountDownLatch latch;
        private final BodySubscriber<Void> subscriber;
        private Subscription subscription;

        private SubscriberWrapper(BodySubscriber<Void> subscriber, CountDownLatch latch) {
            this.subscriber = subscriber;
            this.latch = latch;
        }

        @Override
        public CompletionStage<Void> getBody() {
            return subscriber.getBody();
        }

        @Override
        public void onSubscribe(Subscription subscription) {
            subscriber.onSubscribe(subscription);
            this.subscription = subscription;
            latch.countDown();
        }

        @Override
        public void onNext(List<ByteBuffer> item) {
            subscriber.onNext(item);
        }

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

        @Override
        public void onComplete() {
            subscriber.onComplete();
        }

        public void cancel() {
            subscription.cancel();
            System.out.println("\r\n----------CANCEL!!!------------");
        }
    }

    private static class BodyHandlerWrapper implements BodyHandler<Void> {
        private final CountDownLatch latch = new CountDownLatch(1);
        private final BodyHandler<Void> handler;
        private SubscriberWrapper subscriberWrapper;

        private BodyHandlerWrapper(BodyHandler<Void> handler) {
            this.handler = handler;
        }

        @Override
        public BodySubscriber<Void> apply(ResponseInfo responseInfo) {
            subscriberWrapper = new SubscriberWrapper(handler.apply(responseInfo), latch);
            return subscriberWrapper;
        }

        public void cancel() {
            CompletableFuture.runAsync(() -> {
                try {
                    latch.await();
                    subscriberWrapper.cancel();
                } catch (InterruptedException e) {}
            });
        }
    }

    public static void main(String... args) throws InterruptedException, ExecutionException {
        HttpClient client = HttpClient.newBuilder().build();

        URI uri = URI.create("http://releases.ubuntu.com/18.04.2/ubuntu-18.04.2-desktop-amd64.iso");
        HttpRequest request = HttpRequest.newBuilder().uri(uri).GET().build();

        var handler = HttpResponse.BodyHandlers.ofByteArrayConsumer(b -> System.out.print("#"));
        BodyHandlerWrapper handlerWrapper = new BodyHandlerWrapper(handler);

        client.sendAsync(request, handlerWrapper).thenAccept(b -> System.out.println(b.statusCode()));
        Thread.sleep(1000);
        handlerWrapper.cancel();

        System.out.println("\r\n------Invoke cancel...---------");
        Thread.sleep(2500);
    }
}
Daniel:

Puede cancelar una solicitud HTTP utilizando la java.net.http.HttpClientAPI cancelando el Flow.Subscriptionobjeto que se pasa a la respuesta de BodySubscriber. Debería ser relativamente fácil para envolver trivialmente una de las proporcionadas BodyHandler/ BodySubscriberimplementaciones con el fin de hacerse con el objeto de suscripción. Desafortunadamente no existe una relación entre el cancelmétodo de la CompletableFuturedevuelta por el cliente, y el cancelmétodo de la Flow.Subscriptionpasada al BodySubscriber. La forma correcta de cancelar una solicitud es a través del cancelmétodo de la suscripción.

Cancelación de la suscripción trabajará tanto con el síncrona ( HttpClient::send) y (asíncronos HttpClient::sendAsync) métodos. Se tendrá diferentes efectos sin embargo, dependiendo de si la solicitud fue enviada a través de HTTP / 1.1 o HTTP / 2.0 (con HTTP / 1.1 que causará que la conexión se cierra, con HTTP / 2.0 que hará que la corriente a poner a cero). Y por supuesto que podría tener ningún efecto en absoluto si el último byte de la respuesta ya fue entregado al BodySubscriber.

Supongo que te gusta

Origin http://43.154.161.224:23101/article/api/json?id=203845&siteId=1
Recomendado
Clasificación