当前位置: 首页 > 知识库问答 >
问题:

RESTendpoint在直接访问时起作用,但通过WebClient访问时不起作用

严朝明
2023-03-14

注意:下面是对类似帖子/问题的编辑/修订,试图更好地识别我的问题/问题,并提供更好的代码示例来演示我的问题。

添加注意:代码示例已修改为包括工作代码。

我在同一个spring reactive应用程序中的两台路由器中有两个endpoint。第一个(/v2/demopojo)似乎可以正常工作。第二个(/v2/democlient/demopojo),使用WebClient委托给/v2/demopojo似乎“什么也不做”(尽管记录的输出显示正在调用democlientHandler.add()和democlient.add()))。

当我向/v2/demopojoendpoint发出POST请求时,将调用doFirst()、doOnSuccess()和doFinally()并输出适当的文本(在“Real Life”中,将向存储库中添加一行)。

当我向/v2/democlient/demopojoendpoint发出POST请求时,它返回200 OK状态,但没有输出任何预期的文本(在“实际生活”中,没有向存储库添加任何内容)。

以下文件支持/v2/demopojo终结点...

Demopojo的路由器类实现...

@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的处理程序类实现...

@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();
    }
}
@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)));
    }
}
@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));
    }
}

共有1个答案

亢奇
2023-03-14

我猜这就是你的问题所在。

return request.bodyToMono(DemoPOJO.class)
    .doOnSuccess( demoPOJO -> demoClient.add(demoPOJO))

doonsuccess接受使用者,使用者返回void而不是mono

下面是使用者的详细用法。

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,该democlient#add返回一个单声道 。在这里,您正在破坏链,因为它返回的单声道上没有任何链接,因此它永远不会被订阅,因为它不在事件链中。

return request.bodyToMono(DemoPOJO.class)
    .map( demoPOJO -> {
        return demoClient.add(demoPOJO);
    });

如果您将其更改为map,它可能会起作用。接下来发生的是,它将一个单声道 并将其“映射”到一个单声道 ,该单声道 add函数返回。并且突然它在事件链(回调)中。

 类似资料:
  • 我写这个类是为了帮助从我的android项目的MySQL数据库中获取数据,但每次我运行应用程序时,它都会崩溃,有人能告诉我我的代码出了什么问题吗?我对此是新的,所以任何帮助都将非常感谢。 以下是错误消息所说的内容。 04-15 18:46:58.058 158 37-15837/com.example.tomb3.data e/androidruntime:致命异常:main process:co

  • 问题内容: 我有一个查询说: 我知道事实上有8条记录具有该日期。但是此查询不会提取该日期的记录。这8条记录既有时间又有“短日期”(例如“ 2011年5月31日下午1:42:00”) 作为测试,我将一条记录的日期设置为2011年5月31日,查询将适用于该记录。显然,时间值正在干扰此查询。 我不想将所有日期数据更改为严格的“短日期”格式,而是希望按原样使用它。任何人都可以给我一些想法,让我知道如何进行

  • 问题内容: 我已经设置了版本4 的React。当我直接在浏览器中输入URL时,路由有效,但是当我单击链接时,URL在浏览器上发生了变化(例如http:// localhost:8080 / categories ),但是内容不会更新(但是如果我刷新,它会更新)。 以下是我的设置: 该 Routes.js 设置如下: 我在 Nav.js 中使用的链接如下: 该 App.js 如下: 问题答案: 包装

  • 我的导航有问题。这是我的导航码。 我创建了三个堆栈,如AppStack、StartStack和AuthStack。这些是在createAppContainer()函数中使用的,希望访问这些 this.props.navigation.navigate('App') ... 我可以访问 this.props.navigation.navigate(开始) 和 this.props.navigatio

  • 问题内容: 我正在将文件(pdf,doc,flv等)加载到缓冲区中,并通过脚本将其提供给我的用户。我需要我的脚本能够访问文件,但不允许直接访问它。什么是实现这一目标的最佳方法?我应该使用我的权限来做某事还是使用.htaccess锁定目录? 问题答案: 最安全的方法是将想要保留的文件放到Web根目录之外,就像Damien建议的那样。之所以可行,是因为Web服务器遵循本地文件系统特权,而不是其自身的特

  • 问题内容: 我打电话给我的flask文件。 并且已经将它与uWSGI和nginx一起部署(我遵循了这些说明) 但是,当我收到错误消息时,在浏览器或uWSGI日志中没有任何调试信息。 有任何想法吗? flask_file_name.py: 问题答案: 不能将Flask的debug选项与一起使用,因为它不能在分叉环境中使用。 你会看到502,因为flask / werkzeug没有将任何数据发送到We