问题
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;
- POST in chunks of arrays?
- Capture the response, per POSTed array?
- 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:
- 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();
- 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.
- 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