【问题标题】:Vertx Web Resource Not Found找不到 Vertx Web 资源
【发布时间】:2022-12-29 11:48:09
【问题描述】:

在我正在进行的项目之一中,我将路由动态注册到 Router 上,如下所示。

vertx.eventBus().consumer("REGISTER_ROUTE", handler -> {
      JsonObject message = (JsonObject) handler.body();
      HttpMethod method = HttpMethod.valueOf(message.getString("method"));
      router.route(method, message.getString("url"))
        .order(1)
        .handler(cxt -> cxt.json(new JsonObject().put("message", "This works..!!")));
    });

而这个事件是从另一个像这样的Verticle触发的

vertx.eventBus().send("REGISTER_ROUTE",
        new JsonObject()
          .put("url", "/test-route")
          .put("method", "GET")
      );

问题是在 Windows 机器上这几乎总是有效。但是在 AWS 上的测试 linux 实例上

  • 我通常会收到 404 Not Found 响应而不是实际响应
  • 或者我得到 2 个成功响应 (200) 和一个 404
  • 或者我得到两个 404 和 1 个成功响应

最后两个场景不太确定与数字 3 的相关性(因为此成功/错误响应似乎在 3 个后续请求的循环中刷新)。认为它可能是服务器 Verticle 的实例数。但是修改实例计数也不会改变这种行为。

我有一个 404 的自定义错误处理程序,如下所示

router.errorHandler(404, routingContext -> {
      LOGGER.info("HTTP-404 Error Handler invoked");
      LOGGER.info("Router :" + router.toString() + " Routes Size: " + router.getRoutes().size());
      JsonObject error = new JsonObject()
        .put("error", "Resource not found");
      routingContext.response()
        .setStatusCode(404)
        .putHeader(HttpHeaders.CONTENT_TYPE, "application/json")
        .end(error.toBuffer());
    });

每当收到 404 响应时,我都可以从日志中看到路由器状态确实显示了一条使用给定 PATH 和 HTTP 方法组合声明的路由。

我已经尝试使用 HTTP 方法特定语法(如 router.get(url))注册路由,这似乎也没有任何区别。

Vert.x 版本:4.2.7

JDK:Eclipse 铁木林 11.0.14.1+1

操作系统:EC2 上的 Centos 7

问题是问题并不总是发生,因此识别根本原因并修复它变得越来越困难。

如果其中有任何错误/遗漏,请告诉我。我还创建了一个示例项目here。这是我在实际项目中所拥有的内容的近似复制品。 注意:我在 Windows 上通常不会遇到这个问题(无论出于何种原因)。

【问题讨论】:

    标签: java vert.x vertx4 java-vertx-web


    【解决方案1】:

    App类中,每个Verticle部署了4个实例。

    vertx.deployVerticle(Server.class.getName(), new DeploymentOptions().setInstances(4))
          .compose(server -> {
            return vertx.deployVerticle(RouteRegistration.class.getName(), new DeploymentOptions().setInstances(4))
              .onSuccess(id -> LOGGER.info("Application started Successfully"))
              .onFailure(LOGGER::catching);
          });vertx.deployVerticle(Server.class.getName(), new DeploymentOptions().setInstances(4))
          .compose(server -> {
            return vertx.deployVerticle(RouteRegistration.class.getName(), new DeploymentOptions().setInstances(4))
              .onSuccess(id -> LOGGER.info("Application started Successfully"))
              .onFailure(LOGGER::catching);
          });
    

    这意味着:

    • 将创建共享 HTTP 服务器,并在 Server Verticle 的实例之间平衡传入连接的负载。
    • RouteRegistration verticle 实例发送的消息将在消费者之间进行负载平衡(eventBus.send 是点对点)。

    因此,连接将由具有不同设置的不同路由器处理。

    在您的本地机器上,我不知道为什么会这样,也许您部署了一个实例?

    无论如何,要解决这个问题,您必须在每个路由器实例中具有相同的路由器配置,因此 RouteRegistration 必须 publish 消息以便每个消费者实例都能获得它:

    vertx.eventBus().publish("REGISTER_ROUTE",
          new JsonObject()
            .put("url", "/test-route")
            .put("method", "GET")
        );
    

    【讨论】:

    • 我假设了这一点并且也尝试过。抱歉,我没有在示例复制器代码中更新它。会更新它。但这也没有解决。此外,由于 Router 被声明为静态的,因此不是跨所有 Server verticle 实例的单个副本吗?因此,尽管事件是一个发送事件,但它仍然会在所有实例中注册,不是吗?虽然今天调试时观察到将实例扩展到 4 核 vCPU,但问题并未重现,我现在不知道要检查什么。
    • 我没有注意到路由器被声明为static。这不好:它会同时更新,但它不是线程安全的。您应该为每个 Verticle 实例创建一个 Router 实例。
    • Router 更改为非静态并将事件更改为 publish() 一起解决了我的问题。但即使是现在也不太确定它在开发环境中是如何工作的。无法弄清楚是什么导致它即使在多个实例中也能正常工作。但非常感谢您的帮助。
    • 线程安全问题可能会很明显,也可能不会很明显,具体取决于系统条件。
    【解决方案2】:

    我遇到了同样的问题,然后切换回 deploy (Supplier splv ,DeploymentOptions opt ) ,它 100% 有效。示例:vertx.deployVerticle(()->{ 新 VerticleFirst(路由器,...); }, 部署选项);

    【讨论】:

    • 正如目前所写,您的答案尚不清楚。请edit 添加更多详细信息,以帮助其他人了解这如何解决所提出的问题。你可以找到更多关于如何写出好的答案的信息in the help center
    猜你喜欢
    • 2018-01-03
    • 2018-05-16
    • 2014-03-22
    • 2014-12-15
    • 2018-07-13
    • 1970-01-01
    • 2015-01-28
    • 2019-06-21
    • 1970-01-01
    相关资源
    最近更新 更多