在 Vert.x 中调用同步 API 并使用 WebClient 返回值

问题描述 投票:0回答:2

我是 Vert.x 的新手

我的目标是使用 Rest API,我们称它为 CRUD-API,使用 VertX 提供的 Webclient 类。 CRUD-API 需要一个 ID 并在响应正文中返回一个 json 对象。

我的问题是我的 Consumer verticle 在调用 webclient 执行之前返回。

这是我的代码:

public class WebClientGetById extends AbstractVerticle {

    private String output;

    @Override
    public void start() {
        //DO NOTHING
    }

    public String getById(String myId) {
        output = null;
        vertx.executeBlocking(p -> {
            WebClient client = WebClient.create(vertx);
            client
                    .get(8666, "localhost", "/getById")
                    .putHeader("id", myId)
                    .send()
                    .onSuccess(getSuccesssHandler());
        });
        return output;//THIS LINE IS EXECUTED BEFORE ONSUCCESS
    }

    private Handler<HttpResponse<Buffer>> getSuccesssHandler() {
        return new Handler<HttpResponse<Buffer>>() {
            @Override
            public void handle(HttpResponse<Buffer> response) {
                if (response.statusCode() == HttpResponseStatus.OK.code()) {
                    output = response.bodyAsString();
                } else {
                    output = "Got error from server " + response.statusCode();
                }
            }
        };
    }
}

这是创建网络客户端并尝试使用 CRUD-API 的代码:

public class MyClass {

    public static void main(String[] args) {
        WebClientGetById  verticle = new WebClientGetById ();
        Vertx vertx = Vertx.vertx();
        vertx.deployVerticle(verticle);
        String result = verticle.getById("myId");
        System.out.println(result);
    }
}

从注释行可以看出,在 webclient send() 返回其值之前,执行到了 getById() 的最后一行。所以 null 总是由 getById 返回。

这个类似问题的一部分似乎建议使用 executeBlocking 来实现我的目标。

vertx WebClient.send()方法是阻塞还是非阻塞

但是我试过了,没有用。

那么,Vert.x 实现这个目标的正确方法是什么?

(一段工作代码优于通用的理论解释)

java vert.x
2个回答
0
投票

在 webclient send 返回它的值之前执行到 getById 函数的最后一行

这句话表明你不了解异步编程是如何工作的——在使用vertx之前你需要学习异步编程的基础知识。

executeBlocking 会有所帮助,但似乎没用。

执行阻塞是将阻塞调用卸载到非事件循环线程上——它不会突然改变异步代码的工作方式

return output;//这一行在onSuccess之前执行!!!

是的,这是预期的,异步代码是如何工作的

  1. 没有办法从 onSuccess 或回调中“返回”一个值——你必须通过 futures 和 handlers 组合工作

  2. 如果你想编写能够按顺序执行和运行的异步代码,你应该放弃 java,改用 kotlin 和协程 - 执行 await 调用会给你结果,然后你可以像普通代码一样从函数返回它

你可以通过我的udemy课程了解更多关于如何使用vertx和异步代码https://www.udemy.com/course/backend-development-with-vertx/learn/?referralCode=063C2D57CCB957C5088C

或在https://consulting.aawadia.dev

联系一对一会议

0
投票

executeBlocking
中的promise参数用于将结果异步传递给调用者,前提是:

  • 调用者只能异步返回值

这就是为什么我在以下代码中将返回类型从

string
更改为
Future<String>
的原因。这里的理念是,在异步编程模型中,你必须异步地做所有事情(你可能会争辩说你可以做一些事情来等待结果,但在大多数情况下这是反模式)。可以删除输出字段以简化代码(如果您不介意的话):

import io.netty.handler.codec.http.HttpResponseStatus;
import io.vertx.core.AbstractVerticle;
import io.vertx.core.Future;
import io.vertx.ext.web.client.WebClient;

public class WebClientGetById extends AbstractVerticle {

  @Override
  public void start() {
    //DO NOTHING
  }

  public Future<String> getById(String myId) {
    return vertx.executeBlocking(
        promise -> {
          WebClient client = WebClient.create(vertx);
          client
              .get(8666, "localhost", "/getById")
              .putHeader("id", myId)
              .send()
              .compose(response -> {
                if (response.statusCode() == HttpResponseStatus.OK.code()) {
                  promise.complete(response.bodyAsString());
                } else {
                  promise.fail("Got error from server " + response.statusCode());
                }
                return Future.succeededFuture();
              })
              .onFailure(promise::fail);
        });
  }
}

至于如何优雅地处理

getById
的结果,这里是指南(这是对方法的直接调用,verticle也可以通过事件总线或作为HTTP端点暴露方法,这需要其他工作)

  public void exampleClientCall() {
    // as a client, you should determine how to consume the data fetched from getById
    // eg, to display on terminal, or as response to a http request
    // one thing keep in mind to do it gracefully:
    // - always consider the successful and failed cases
    
    getById("xxxx")
        .onSuccess(ret -> {
          // display on stdout or response to http request with ret
        })
        .onFailure(exception -> {
          // please never forget error handling
          // do some log here
          // display on stdout or response to http request with a default value or proper exception message 
        });
  }
© www.soinside.com 2019 - 2024. All rights reserved.