如何在 Spring WebFlux 中的一个 Mono 中基于另一个请求执行连续的 Web 请求?
How to perform consecutive web requests based on another request in one Mono in Spring WebFlux?
我想通过 Spring WebFlux 和给定的 REST-API 执行以下操作:
- 检索文件名列表 (GET /files)
- 删除每个检索到的文件(每个删除 /files/local/{文件名})
问题是我无法将这两个操作组合到 "one" Mono 实例。我当前的实现是不够的,因为它阻止 Mono 实例立即执行 api 调用,而不是被动地执行它们。
我的非响应式实现:
public Mono cleanUpUploadedFiles() {
WebClient webClient = this.getWebClient();
// get all files / directories
Mono<FilesOverview> filesOverviewMono = this.getResource("/files", FilesOverview.class);
FilesOverview filesOverview = filesOverviewMono.block(); // TODO: prevent blocking mono
// delete file / directory one by one
for (FileOverview file : filesOverview.getFiles()) {
ClientResponse clientResponse;
clientResponse = webClient
.delete()
.uri(String.format("/files/local/%s", file.getName()))
.exchange()
.block(); // TODO: prevent blocking mono
if (clientResponse == null) {
return Mono.error(new MyException(String.format("could not execute rest call to delete uploaded files with uuid %s", file.getName())));
}
HttpStatus clientResponseStatusCode = clientResponse.statusCode();
if (clientResponseStatusCode.isError()) {
return Mono.error(new MyException(String.format("cannot delete uploaded files with uuid %s", file.getName())));
}
}
return Mono.empty(); // TODO: return Mono instance performing everything reactive without blocking
}
如何在一个 Mono 实例中响应式执行连续的 Web 请求?
应该如下所示:
public Mono cleanUpUploadedFiles() {
WebClient webClient = this.getWebClient();
// get all files / directories
Mono<FilesOverview> filesOverviewMono = this.getResource("/files", FilesOverview.class);
return filesOverviewMono.flatMap(file ->{
return webClient
.delete()
.uri(String.format("/files/local/%s", file.getName()))
.exchange()
.flatMap()//normal scenario
.onErrorResume()//error
.switchIfEmpty();//empty body
//each of these will give you a Mono, so you would need to
//transform all of them to finally give a Mono as needed by
//the method
}).flatMap();//transform
}
您应该链接所有操作以创建反应流。
通常,您获取一个操作的输出并将其用作另一个操作的输入。
Project Reactor 提供了许多 map
和 flatMap
运算符来完成此操作。
在您的示例中,您应该检索文件列表,然后将每个元素映射到删除操作,如下所示:
public Mono<Void> cleanUpUploadedFiles() {
return getResource("/files", FilesOverview.class) // Retrieve the file list
.flatMapIterable(FilesOverview::getFiles) // Create a Flux from the file list
.map(FileOverview::getName) // Map the file overview to the file name
.flatMap(this::deleteFile) // Delete the file
.then(); // Just return a Mono<Void>
}
private Mono<Void> deleteFile(String fileName) {
return getWebClient()
.delete()
.uri("/files/local/{fileName}", fileName)
.exchange() // Perform the delete operation
.onErrorMap(e -> new MyException(String.format("could not execute rest call to delete uploaded files with uuid %s", fileName))) // Handle errors
.map(ClientResponse::statusCode) // Map the response to the status code
.flatMap(statusCode -> {
// If the operation was not successful signal an error
if (statusCode.isError()) {
return Mono.error(new MyException(String.format("cannot delete uploaded files with uuid %s", fileName)));
}
// Otherwise return a Mono<Void>
return Mono.empty();
});
}
我想通过 Spring WebFlux 和给定的 REST-API 执行以下操作:
- 检索文件名列表 (GET /files)
- 删除每个检索到的文件(每个删除 /files/local/{文件名})
问题是我无法将这两个操作组合到 "one" Mono 实例。我当前的实现是不够的,因为它阻止 Mono 实例立即执行 api 调用,而不是被动地执行它们。
我的非响应式实现:
public Mono cleanUpUploadedFiles() {
WebClient webClient = this.getWebClient();
// get all files / directories
Mono<FilesOverview> filesOverviewMono = this.getResource("/files", FilesOverview.class);
FilesOverview filesOverview = filesOverviewMono.block(); // TODO: prevent blocking mono
// delete file / directory one by one
for (FileOverview file : filesOverview.getFiles()) {
ClientResponse clientResponse;
clientResponse = webClient
.delete()
.uri(String.format("/files/local/%s", file.getName()))
.exchange()
.block(); // TODO: prevent blocking mono
if (clientResponse == null) {
return Mono.error(new MyException(String.format("could not execute rest call to delete uploaded files with uuid %s", file.getName())));
}
HttpStatus clientResponseStatusCode = clientResponse.statusCode();
if (clientResponseStatusCode.isError()) {
return Mono.error(new MyException(String.format("cannot delete uploaded files with uuid %s", file.getName())));
}
}
return Mono.empty(); // TODO: return Mono instance performing everything reactive without blocking
}
如何在一个 Mono 实例中响应式执行连续的 Web 请求?
应该如下所示:
public Mono cleanUpUploadedFiles() {
WebClient webClient = this.getWebClient();
// get all files / directories
Mono<FilesOverview> filesOverviewMono = this.getResource("/files", FilesOverview.class);
return filesOverviewMono.flatMap(file ->{
return webClient
.delete()
.uri(String.format("/files/local/%s", file.getName()))
.exchange()
.flatMap()//normal scenario
.onErrorResume()//error
.switchIfEmpty();//empty body
//each of these will give you a Mono, so you would need to
//transform all of them to finally give a Mono as needed by
//the method
}).flatMap();//transform
}
您应该链接所有操作以创建反应流。
通常,您获取一个操作的输出并将其用作另一个操作的输入。
Project Reactor 提供了许多 map
和 flatMap
运算符来完成此操作。
在您的示例中,您应该检索文件列表,然后将每个元素映射到删除操作,如下所示:
public Mono<Void> cleanUpUploadedFiles() {
return getResource("/files", FilesOverview.class) // Retrieve the file list
.flatMapIterable(FilesOverview::getFiles) // Create a Flux from the file list
.map(FileOverview::getName) // Map the file overview to the file name
.flatMap(this::deleteFile) // Delete the file
.then(); // Just return a Mono<Void>
}
private Mono<Void> deleteFile(String fileName) {
return getWebClient()
.delete()
.uri("/files/local/{fileName}", fileName)
.exchange() // Perform the delete operation
.onErrorMap(e -> new MyException(String.format("could not execute rest call to delete uploaded files with uuid %s", fileName))) // Handle errors
.map(ClientResponse::statusCode) // Map the response to the status code
.flatMap(statusCode -> {
// If the operation was not successful signal an error
if (statusCode.isError()) {
return Mono.error(new MyException(String.format("cannot delete uploaded files with uuid %s", fileName)));
}
// Otherwise return a Mono<Void>
return Mono.empty();
});
}