Quarkus 中的 Vertx Web 路由和 Reactive Pg Client 问题

Vertx web routes and Reactive Pg Client issue in Quarkus

该应用程序基于以下堆栈:

完整代码为here.

我通过 @Observes Router 创建了一个路由器。

@ApplicationScoped
public class RoutesObserver {

    @Inject PostsHandlers handlers;

    public void route(@Observes Router router) {
        router.get("/posts").produces("application/json").handler(handlers::getAll);
        router.post("/posts").consumes("application/json").handler(handlers::save);
        router.get("/posts/:id").produces("application/json").handler(handlers::get);
        router.put("/posts/:id").consumes("application/json").handler(handlers::update);
        router.delete("/posts/:id").handler(handlers::delete);

        router.get("/hello").handler(rc -> rc.response().end("Hello from my route"));
    }

}

并将处理程序提取到一个独立的 bean 中。

@ApplicationScoped
class PostsHandlers {
    private static final Logger LOGGER = Logger.getLogger(PostsHandlers.class.getSimpleName());

    PostRepository posts;

    ObjectMapper objectMapper;

    @Inject
    public PostsHandlers(PostRepository posts, ObjectMapper objectMapper) {
        this.posts = posts;
        this.objectMapper = objectMapper;
    }

    public void getAll(RoutingContext rc) {
        this.posts.findAll().thenAccept(
                data -> rc.response()
                        .write(toJson(data))
                        .end()

        );
    }
   //... other methods.

}

而 PostRepository 使用了 Java 8 CompletionStage API.

@ApplicationScoped
public class PostRepository {
    private static final Logger LOGGER = LoggerFactory.getLogger(PostRepository.class);

    private final PgPool client;

    @Inject
    public PostRepository(PgPool _client) {
        this.client = _client;
    }

    public CompletionStage<List<Post>> findAll() {
        return client.query("SELECT * FROM posts ORDER BY id ASC")
                .execute()
                .thenApply(rs -> StreamSupport.stream(rs.spliterator(), false)
                        .map(this::from)
                        .collect(Collectors.toList())
                );
    }

当我 运行 这个应用程序并试图访问 /posts 时。它被冻结并且没有打印任何响应。

使用write方法时,需要(预先)设置content-length header.

有几种方法可以解决这个问题:

  1. 您可以使用 .end(toJson(data)) 而不是 write(...).end() - 它会自动计算长度
  2. 您可以使用 .putHeader("transfer-encoding", "chunked")write(...).end() - 如果您计划检索多个结果,这很有趣,因为它将每个块一个一个地写入客户端,避免一次发送大量有效负载去
  3. 您可以将 content-length 设置为:
String result = toJson(data);
rc.response()
   .putHeader("content-length", Long.toString(result.length()))
   .write(result)
   .end();