Splitting a WebClient Post of a Streaming Flux into JSON Arrays

馋奶兔 提交于 2019-12-11 06:49:08

问题


I am using a third-party REST controller which accepts an array of JSON objects and returns a single object response. When I POST from a WebClient using a limited Flux the code works (I assume, because the Flux completes).

However, when the Flux is potentially unlimited, how do I;

  1. POST in chunks of arrays?
  2. Capture the response, per POSTed array?
  3. Stop the transmission of the Flux?

Here is my bean;

public class Car implements Serializable {

    Long id;

    public Car() {}
    public Car(Long id) { this.id = id; }
    public Long getId() {return id; }
    public void setId(Long id) { this.id = id; }
}

This is how I assume that the third-party client looks like;

@RestController
public class ThirdPartyServer {

    @PostMapping("/cars")
    public CarResponse doCars(@RequestBody List<Car> cars) {
        System.err.println("Got " + cars);
        return new CarResponse("OK");
    }
}

And here is my code. When I POST flux2 , on completion a JSON array is sent. However, when I POST flux1, nothing is sent after the first take(5). How do POST the next chunks of 5?

@Component
public class MyCarClient {

    public void sendCars() {

//      Flux<Car> flux1 = Flux.interval(Duration.ofMillis(250)).map(i -> new Car(i));
        Flux<Car> flux2 = Flux.range(1, 10).map(i -> new Car((long) i));

        WebClient client = WebClient.create("http://localhost:8080");
        client
            .post()
            .uri("/cars")
            .contentType(MediaType.APPLICATION_JSON)
            .body(flux2, Car.class) 
//          .body(flux1.take(5).collectList(), new ParameterizedTypeReference<List<Car>>() {})
            .exchange()
            .subscribe(r -> System.err.println(r.statusCode()));
    }
}

回答1:


  1. How do I POST in chunks of arrays?

Use one of the variants of Flux.window to split the main flux into windowed fluxes, and then send the requests using the windowed fluxes via .flatMap

        Flux<Car> flux1 = Flux.interval(Duration.ofMillis(250)).map(i -> new Car(i));

        WebClient client = WebClient.create("http://localhost:8080");
        Disposable disposable = flux1
                // 1
                .window(5)
                .flatMap(windowedFlux -> client
                        .post()
                        .uri("/cars")
                        .contentType(MediaType.APPLICATION_JSON)
                        .body(windowedFlux, Car.class)
                        .exchange()
                        // 2
                        .doOnNext(response -> System.out.println(response.statusCode()))
                        .flatMap(response -> response.bodyToMono(...)))
                .subscribe();

        Thread.sleep(10000);

        // 3
        disposable.dispose();

  1. How do I capture the response, per POSTed array?

You can analyze the response via operators after .exchange().

In the example I provided, the response can be seen in the doOnNext operator, but you can use any operator that operates on onNext signals, such as map or handle.

Be sure to read the response body fully to ensure the connection is returned back to the pool (see note). Here, I have used .bodyToMono, but any .body or .toEntity method will work.

  1. Stop the transmission of the Flux?

When using the subscribe method as you have done, you can stop the flow using the returned disposable.dispose().

Alternatively, you can return the Flux from the sendCars() method and delegate the subscription and disposing to the caller.

Note that in the example I provided, I just used Thread.sleep() to simulate waiting. In a real application, you should use something more advanced, and avoid Thread.sleep()



来源:https://stackoverflow.com/questions/55523944/splitting-a-webclient-post-of-a-streaming-flux-into-json-arrays

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!