REST 端点在直接访问时有效,但在通过 WebClient 访问时无效
REST endpoint works when directly accessed, but not when accessed via WebClient
注意:下面是一个edit/revision类似的post/question,试图更好地识别我的issue/question,并提供更好的代码示例来说明我的问题。
添加注释:代码示例已修改为包含工作代码。
我在同一个 spring 响应式应用程序的两个路由器中有两个端点。第一个 (/v2/DemoPOJO) 似乎工作正常。第二个(/v2/DemoClient/DemoPOJO),它使用 WebClient 委托给 /v2/DemoPOJO 似乎 "do nothing"(尽管记录的输出显示 DemoClientHandler.add() 和 DemoClient.add() 正在被调用。
当我向 /v2/DemoPOJO 端点发出 POST 请求时,doFirst(),doOnSuccess() 和 doFinally() 被调用并输出适当的文本(在 "real life" 中,一行被添加到存储库中) .
当我向 /v2/DemoClient/DemoPOJO 端点发出 POST 请求时,它 returns 200 OK 状态,但是 none 的预期文本被输出(在 "real life" 中,没有任何内容被添加到存储库中)。
以下文件支持 /v2/DemoPOJO 端点...
DemoPOJO 的路由器 class 实现...
@Configuration
public class DemoPOJORouter {
private Logger logger = LoggerFactory.getLogger(DemoPOJORouter.class);
@Bean
public RouterFunction<ServerResponse> demoPOJORoute(DemoPOJOHandler requestHandler) {
logger.debug("DemoPOJORouter.demoPOJORoute( DemoPOJOHandler )");
return nest(path("/v2"),
nest(accept(APPLICATION_JSON),
RouterFunctions.route(RequestPredicates.POST("/DemoPOJO"), requestHandler::add)));
}
}
DemoPOJO 的处理程序class 实现...
@Component
public class DemoPOJOHandler {
private Logger logger = LoggerFactory.getLogger(DemoPOJOHandler.class);
public Mono<ServerResponse> add(ServerRequest request) {
logger.debug("DemoPOJOHandler.add( ServerRequest )");
return request.bodyToMono(DemoPOJO.class).doFirst(() -> System.out.println("-> doFirst()."))
.doOnSuccess(demoPOJO -> System.out.println("Received >> " + demoPOJO.toString()))
.then(ServerResponse.accepted().build())
.doOnError(e -> System.out.println("-> doOnError()"))
.doFinally(demoPOJO -> System.out.println("-> doFinally()"));
}
}
DemoPOJO 实现j...
public class DemoPOJO {
private Logger logger = LoggerFactory.getLogger(DemoPOJO.class);
public static final String DEF_NAME = "DEFAULT NAME";
public static final int DEF_VALUE = 99;
private int id;
private String name;
private int value;
public DemoPOJO(@JsonProperty("id") int id, @JsonProperty("name") String name, @JsonProperty("value") int value) {
logger.debug("DemoPOJO.DemoPOJO( {}, {}, {} )", id, name, value);
this.id = id;
this.name = name;
this.value = value;
}
/*
* setters and getters go here
*/
public String toString() {
logger.debug("DemoPOJO.toString()");
StringBuilder builder = new StringBuilder();
builder.append(id);
builder.append(" :: ");
builder.append(name);
builder.append(" :: ");
builder.append(value);
return builder.toString();
}
}
以下文件支持 /v2/DemoClient/DemoPOJO 端点...
DemoClient 的路由器实现...
@Configuration
public class DemoClientRouter {
private Logger logger = LoggerFactory.getLogger(DemoClientRouter.class);
@Bean
public RouterFunction<ServerResponse> clientRoutes(DemoClientHandler requestHandler) {
logger.debug("DemoClientRouter.route( DemoClientHandler )");
return nest(path("/v2/DemoClient"),
nest(accept(APPLICATION_JSON),
RouterFunctions.route(RequestPredicates.POST("/DemoPOJO"), requestHandler::add)));
}
}
DemoClient 的处理程序实现...
@Component
public class DemoClientHandler {
private Logger logger = LoggerFactory.getLogger(mil.navy.demo.demopojo.DemoPOJOHandler.class);
@Autowired
DemoClient demoClient;
public Mono<ServerResponse> add(ServerRequest request) {
logger.debug("DemoClientOHandler.add( ServerRequest )");
// THIS CODE
return request.bodyToMono(DemoPOJO.class).flatMap(demoPOJO -> demoClient.add(demoPOJO))
.then(ServerResponse.accepted().build());
// REPLACES THIS CODE
/*
return request.bodyToMono(DemoPOJO.class).doOnSuccess( demoPOJO -> demoClient.add(demoPOJO))
.then(ServerResponse.ok().build())
.switchIfEmpty(ServerResponse.badRequest().build());
*/
}
}
DemoClient 的 WebClient 实现...
@Component
public class DemoClient {
private Logger logger = LoggerFactory.getLogger(DemoClient.class);
private final WebClient client;
public DemoClient() {
client = WebClient.create();
}
public Mono<Boolean> add(DemoPOJO demoPOJO) {
logger.debug("DemoClient.add( DemoPOJO )");
logger.debug("DemoClient.add() >> DemoPOJO -> {}", demoPOJO.toString());
return client.post().uri("http://localhost:8080/v2/DemoPOJO")
.accept(MediaType.APPLICATION_JSON)
.syncBody(demoPOJO)
.exchange()
.flatMap(response -> response.bodyToMono(Boolean.class));
}
}
这就是我猜你的问题所在。
return request.bodyToMono(DemoPOJO.class)
.doOnSuccess( demoPOJO -> demoClient.add(demoPOJO))
doOnSuccess
取一个消费者,一个消费者returnsvoid
notMono<Void>
.
这里是 Consumer
.
的详细用法
Mono.just("hello")
.doOnSuccess(new Consumer<String>() {
@Override
public void accept(String s) {
// See here, it returns void
}
});
让我们看一些例子:
Mono<String> helloWorld = Mono.just("Hello")
.doOnSuccess(string -> {
// This will never be executed because
// it is just declared and never subscribed to
Mono.just(string + " world");
});
helloWorld.doOnSuccess(string -> {
// This will print out Hello
System.out.println(string);
});
Mono<String> hello = Mono.just("Hello")
.doOnSuccess(string -> {
// This will print out Hello World
System.out.println(string + " World");
});
// hello hasn't been changed
hello.map(string -> {
// This will also print out Hello World
System.out.println(string + " World");
});
// This prints hello world to after we mapped it
Mono<String> helloworld = Mono.just("hello")
.map(s -> s + " World")
.doOnSuccess(System.out::println);
// Now this is what you are essentially doing
// See how this is wrong?
Mono<DemoPOJO> demoPOJO = request.bodyToMono(DemoPOJO.class)
.doOnSuccess( demoPOJO -> Mono.empty() );
你正在调用 demoClient#add
那 returns a Mono<Void>
这里你打破了链条,因为没有任何东西链接到它返回的 Mono 上,所以它永远不会被订阅,因为它不在事件链中。
return request.bodyToMono(DemoPOJO.class)
.map( demoPOJO -> {
return demoClient.add(demoPOJO);
});
如果将其更改为 map
,它可能会起作用。然后发生的事情是它将 Mono<DemoPojo>
和 "mapping" 带到 add
函数返回的 Mono<Void>
。突然它在事件链中(回调)。
注意:下面是一个edit/revision类似的post/question,试图更好地识别我的issue/question,并提供更好的代码示例来说明我的问题。
添加注释:代码示例已修改为包含工作代码。
我在同一个 spring 响应式应用程序的两个路由器中有两个端点。第一个 (/v2/DemoPOJO) 似乎工作正常。第二个(/v2/DemoClient/DemoPOJO),它使用 WebClient 委托给 /v2/DemoPOJO 似乎 "do nothing"(尽管记录的输出显示 DemoClientHandler.add() 和 DemoClient.add() 正在被调用。
当我向 /v2/DemoPOJO 端点发出 POST 请求时,doFirst(),doOnSuccess() 和 doFinally() 被调用并输出适当的文本(在 "real life" 中,一行被添加到存储库中) .
当我向 /v2/DemoClient/DemoPOJO 端点发出 POST 请求时,它 returns 200 OK 状态,但是 none 的预期文本被输出(在 "real life" 中,没有任何内容被添加到存储库中)。
以下文件支持 /v2/DemoPOJO 端点...
DemoPOJO 的路由器 class 实现...
@Configuration
public class DemoPOJORouter {
private Logger logger = LoggerFactory.getLogger(DemoPOJORouter.class);
@Bean
public RouterFunction<ServerResponse> demoPOJORoute(DemoPOJOHandler requestHandler) {
logger.debug("DemoPOJORouter.demoPOJORoute( DemoPOJOHandler )");
return nest(path("/v2"),
nest(accept(APPLICATION_JSON),
RouterFunctions.route(RequestPredicates.POST("/DemoPOJO"), requestHandler::add)));
}
}
DemoPOJO 的处理程序class 实现...
@Component
public class DemoPOJOHandler {
private Logger logger = LoggerFactory.getLogger(DemoPOJOHandler.class);
public Mono<ServerResponse> add(ServerRequest request) {
logger.debug("DemoPOJOHandler.add( ServerRequest )");
return request.bodyToMono(DemoPOJO.class).doFirst(() -> System.out.println("-> doFirst()."))
.doOnSuccess(demoPOJO -> System.out.println("Received >> " + demoPOJO.toString()))
.then(ServerResponse.accepted().build())
.doOnError(e -> System.out.println("-> doOnError()"))
.doFinally(demoPOJO -> System.out.println("-> doFinally()"));
}
}
DemoPOJO 实现j...
public class DemoPOJO {
private Logger logger = LoggerFactory.getLogger(DemoPOJO.class);
public static final String DEF_NAME = "DEFAULT NAME";
public static final int DEF_VALUE = 99;
private int id;
private String name;
private int value;
public DemoPOJO(@JsonProperty("id") int id, @JsonProperty("name") String name, @JsonProperty("value") int value) {
logger.debug("DemoPOJO.DemoPOJO( {}, {}, {} )", id, name, value);
this.id = id;
this.name = name;
this.value = value;
}
/*
* setters and getters go here
*/
public String toString() {
logger.debug("DemoPOJO.toString()");
StringBuilder builder = new StringBuilder();
builder.append(id);
builder.append(" :: ");
builder.append(name);
builder.append(" :: ");
builder.append(value);
return builder.toString();
}
}
以下文件支持 /v2/DemoClient/DemoPOJO 端点...
DemoClient 的路由器实现...
@Configuration
public class DemoClientRouter {
private Logger logger = LoggerFactory.getLogger(DemoClientRouter.class);
@Bean
public RouterFunction<ServerResponse> clientRoutes(DemoClientHandler requestHandler) {
logger.debug("DemoClientRouter.route( DemoClientHandler )");
return nest(path("/v2/DemoClient"),
nest(accept(APPLICATION_JSON),
RouterFunctions.route(RequestPredicates.POST("/DemoPOJO"), requestHandler::add)));
}
}
DemoClient 的处理程序实现...
@Component
public class DemoClientHandler {
private Logger logger = LoggerFactory.getLogger(mil.navy.demo.demopojo.DemoPOJOHandler.class);
@Autowired
DemoClient demoClient;
public Mono<ServerResponse> add(ServerRequest request) {
logger.debug("DemoClientOHandler.add( ServerRequest )");
// THIS CODE
return request.bodyToMono(DemoPOJO.class).flatMap(demoPOJO -> demoClient.add(demoPOJO))
.then(ServerResponse.accepted().build());
// REPLACES THIS CODE
/*
return request.bodyToMono(DemoPOJO.class).doOnSuccess( demoPOJO -> demoClient.add(demoPOJO))
.then(ServerResponse.ok().build())
.switchIfEmpty(ServerResponse.badRequest().build());
*/
}
}
DemoClient 的 WebClient 实现...
@Component
public class DemoClient {
private Logger logger = LoggerFactory.getLogger(DemoClient.class);
private final WebClient client;
public DemoClient() {
client = WebClient.create();
}
public Mono<Boolean> add(DemoPOJO demoPOJO) {
logger.debug("DemoClient.add( DemoPOJO )");
logger.debug("DemoClient.add() >> DemoPOJO -> {}", demoPOJO.toString());
return client.post().uri("http://localhost:8080/v2/DemoPOJO")
.accept(MediaType.APPLICATION_JSON)
.syncBody(demoPOJO)
.exchange()
.flatMap(response -> response.bodyToMono(Boolean.class));
}
}
这就是我猜你的问题所在。
return request.bodyToMono(DemoPOJO.class)
.doOnSuccess( demoPOJO -> demoClient.add(demoPOJO))
doOnSuccess
取一个消费者,一个消费者returnsvoid
notMono<Void>
.
这里是 Consumer
.
Mono.just("hello")
.doOnSuccess(new Consumer<String>() {
@Override
public void accept(String s) {
// See here, it returns void
}
});
让我们看一些例子:
Mono<String> helloWorld = Mono.just("Hello")
.doOnSuccess(string -> {
// This will never be executed because
// it is just declared and never subscribed to
Mono.just(string + " world");
});
helloWorld.doOnSuccess(string -> {
// This will print out Hello
System.out.println(string);
});
Mono<String> hello = Mono.just("Hello")
.doOnSuccess(string -> {
// This will print out Hello World
System.out.println(string + " World");
});
// hello hasn't been changed
hello.map(string -> {
// This will also print out Hello World
System.out.println(string + " World");
});
// This prints hello world to after we mapped it
Mono<String> helloworld = Mono.just("hello")
.map(s -> s + " World")
.doOnSuccess(System.out::println);
// Now this is what you are essentially doing
// See how this is wrong?
Mono<DemoPOJO> demoPOJO = request.bodyToMono(DemoPOJO.class)
.doOnSuccess( demoPOJO -> Mono.empty() );
你正在调用 demoClient#add
那 returns a Mono<Void>
这里你打破了链条,因为没有任何东西链接到它返回的 Mono 上,所以它永远不会被订阅,因为它不在事件链中。
return request.bodyToMono(DemoPOJO.class)
.map( demoPOJO -> {
return demoClient.add(demoPOJO);
});
如果将其更改为 map
,它可能会起作用。然后发生的事情是它将 Mono<DemoPojo>
和 "mapping" 带到 add
函数返回的 Mono<Void>
。突然它在事件链中(回调)。