为什么在将 Mono<Void> 映射到 Mono<String> 时收到空字符串?
why do I receive an empty string when mapping Mono<Void> to Mono<String>?
我正在使用 Spring WebFlux 开发 API REST,但我在上传文件时遇到问题。它们已存储,但我没有得到预期的 return 值。
我就是这样做的:
- 收到 Flux<零件>
- Cast Part 到 FilePart。
- 使用 transferTo() 保存零件(这个 return 一个 Mono
)
- 使用文件名将 Mono
映射到 Mono。
- Return Flux
到客户端。
我希望文件名被 returned,但客户端得到一个空字符串。
控制器代码
@PostMapping(value = "/muscles/{id}/image")
public Flux<String> updateImage(@PathVariable("id") String id, @RequestBody Flux<Part> file) {
log.info("REST request to update image to Muscle");
return storageService.saveFiles(file);
}
存储服务
public Flux<String> saveFiles(Flux<Part> parts) {
log.info("StorageService.saveFiles({})", parts);
return
parts
.filter(p -> p instanceof FilePart)
.cast(FilePart.class)
.flatMap(file -> saveFile(file));
}
private Mono<String> saveFile(FilePart filePart) {
log.info("StorageService.saveFile({})", filePart);
String filename = DigestUtils.sha256Hex(filePart.filename() + new Date());
Path target = rootLocation.resolve(filename);
try {
Files.deleteIfExists(target);
File file = Files.createFile(target).toFile();
return filePart.transferTo(file)
.map(r -> filename);
} catch (IOException e) {
throw new RuntimeException(e);
}
}
FilePart.transferTo() returns Mono 即常量空。然后,在那之后的地图从未被执行过。我通过这样做解决了它:
private Mono<String> saveFile(FilePart filePart) {
log.info("StorageService.saveFile({})", filePart);
String filename = DigestUtils.sha256Hex(filePart.filename() + new Date());
Path target = rootLocation.resolve(filename);
try {
Files.deleteIfExists(target);
File file = Files.createFile(target).toFile();
return filePart
.transferTo(file)
.doOnSuccess(data -> log.info("do something..."))
.thenReturn(filename);
} catch (IOException e) {
throw new RuntimeException(e);
}
}
FilePart.transferTo()
returns Mono<Void>
,当操作完成时发出信号 - 这意味着反应式 Publisher
只会发布 onComplete
/onError
信号并且永远不会在此之前发布值。
这意味着 map
操作从未执行过,因为它只给出了源发布的元素。
您可以 return 文件的名称和仍然链式反应运算符,如下所示:
return part.transferTo(file).thenReturn(part.filename());
禁止在反应管道中使用 block
运算符,它 even throws an exception at runtime as of Reactor 3.2。
使用subscribe
作为替代方案也不好,因为subscribe
会将传输过程与您的请求处理分离,使它们以不同的执行顺序发生。这意味着您的服务器可以完成请求处理并关闭 HTTP 连接,而另一部分仍在尝试读取文件部分以将其复制到磁盘上。这可能会在运行时以微妙的方式失败。
我正在使用 Spring WebFlux 开发 API REST,但我在上传文件时遇到问题。它们已存储,但我没有得到预期的 return 值。
我就是这样做的:
- 收到 Flux<零件>
- Cast Part 到 FilePart。
- 使用 transferTo() 保存零件(这个 return 一个 Mono
) - 使用文件名将 Mono
映射到 Mono 。 - Return Flux
到客户端。
我希望文件名被 returned,但客户端得到一个空字符串。
控制器代码
@PostMapping(value = "/muscles/{id}/image")
public Flux<String> updateImage(@PathVariable("id") String id, @RequestBody Flux<Part> file) {
log.info("REST request to update image to Muscle");
return storageService.saveFiles(file);
}
存储服务
public Flux<String> saveFiles(Flux<Part> parts) {
log.info("StorageService.saveFiles({})", parts);
return
parts
.filter(p -> p instanceof FilePart)
.cast(FilePart.class)
.flatMap(file -> saveFile(file));
}
private Mono<String> saveFile(FilePart filePart) {
log.info("StorageService.saveFile({})", filePart);
String filename = DigestUtils.sha256Hex(filePart.filename() + new Date());
Path target = rootLocation.resolve(filename);
try {
Files.deleteIfExists(target);
File file = Files.createFile(target).toFile();
return filePart.transferTo(file)
.map(r -> filename);
} catch (IOException e) {
throw new RuntimeException(e);
}
}
FilePart.transferTo() returns Mono
private Mono<String> saveFile(FilePart filePart) {
log.info("StorageService.saveFile({})", filePart);
String filename = DigestUtils.sha256Hex(filePart.filename() + new Date());
Path target = rootLocation.resolve(filename);
try {
Files.deleteIfExists(target);
File file = Files.createFile(target).toFile();
return filePart
.transferTo(file)
.doOnSuccess(data -> log.info("do something..."))
.thenReturn(filename);
} catch (IOException e) {
throw new RuntimeException(e);
}
}
FilePart.transferTo()
returns Mono<Void>
,当操作完成时发出信号 - 这意味着反应式 Publisher
只会发布 onComplete
/onError
信号并且永远不会在此之前发布值。
这意味着 map
操作从未执行过,因为它只给出了源发布的元素。
您可以 return 文件的名称和仍然链式反应运算符,如下所示:
return part.transferTo(file).thenReturn(part.filename());
禁止在反应管道中使用 block
运算符,它 even throws an exception at runtime as of Reactor 3.2。
使用subscribe
作为替代方案也不好,因为subscribe
会将传输过程与您的请求处理分离,使它们以不同的执行顺序发生。这意味着您的服务器可以完成请求处理并关闭 HTTP 连接,而另一部分仍在尝试读取文件部分以将其复制到磁盘上。这可能会在运行时以微妙的方式失败。