You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Vertx迁移Quarkus后首次请求成功后续报HTTP 404错误

问题分析:Vert.x迁移Quarkus后首次请求成功、后续均返回404

问题现象

将基于多Verticle的Vert.x应用迁移至Quarkus后,应用启动就绪后首次HTTP请求可正常响应,但后续所有请求均返回404错误。

核心原因定位

1. 重复HttpServer实例冲突

你的代码中手动创建了一个独立的HttpServer并监听8080端口,但Quarkus默认已经启动了一个共享的Vert.x HttpServer实例监听该端口。首次请求可能被你手动创建的服务器处理,但后续请求会被Quarkus内置的HttpServer接管——而内置服务器的Router中并未配置你定义的路由规则,因此返回404。

2. Verticle生命周期管理错误

你给HttpVerticle添加了@ApplicationScoped注解,让CDI容器管理其生命周期,但Quarkus中Verticle的正确管理方式是使用@Verticle注解。这种错误的注解方式会导致Verticle初始化逻辑与Quarkus的Vert.x扩展冲突,进一步加剧路由处理的混乱。

3. 错误日志验证

从报错栈可以看到,后续请求由Quarkus的Resteasy Reactive处理链(org.jboss.resteasy.reactive.server.handlers.RestInitialHandler)接管,而非你自定义的Router,这直接证明请求未进入你配置的路由规则。

解决方向

方案1:整合到Quarkus内置Router(推荐)

移除手动创建HttpServer的逻辑,直接使用Quarkus提供的共享Router实例,让所有请求统一由内置服务器处理:

import io.quarkus.vertx.Verticle;
import io.vertx.ext.web.Router;
import io.vertx.ext.web.handler.BodyHandler;
import jakarta.inject.Inject;

@Verticle // 替换@ApplicationScoped,让Quarkus正确管理Verticle生命周期
public class HttpVerticle extends io.vertx.core.AbstractVerticle {

    @Inject
    Router router; // 注入Quarkus共享的Router实例

    @Override
    public void start() {
        // 直接在共享Router上添加路由
        router.route().handler(BodyHandler.create());
        router.get("/event/:eventID").handler(this::handleTrackingEvent);
        router.get("/cache/fill").handler(this::fillCacheWithData);
        router.get("/cache/purge").handler(this::purgeCache);
        router.get("/health/check").handler(this::checkHealth);
        
        // 无需手动创建HttpServer和监听端口,Quarkus已自动处理
    }

    // 原有的handleTrackingEvent、fillCacheWithData等方法保持不变
}

方案2:使用Quarkus路由注解简化开发

如果不需要保留Verticle结构,可以直接用@Route注解定义路由,完全替代自定义Verticle:

import io.quarkus.vertx.web.Route;
import io.quarkus.vertx.web.RoutingExchange;
import io.vertx.core.eventbus.EventBus;
import jakarta.inject.Inject;
import org.jboss.logging.Logger;

@ApplicationScoped
public class HttpRoutes {

    @Inject
    EventBus eb;
    private static final Logger LOGGER = Logger.getLogger(HttpRoutes.class.getName());

    @Route(path = "/health/check", methods = Route.HttpMethod.GET)
    public void checkHealth(RoutingExchange exchange) {
        exchange.response()
                .setStatusCode(200)
                .putHeader("content-type", "application/json")
                .end();
    }

    @Route(path = "/cache/purge", methods = Route.HttpMethod.GET)
    public void purgeCache(RoutingExchange exchange) {
        eb.send(Constants.REDIS_PURGE_EVENTBUS_ADDRESS, "");
        eb.send(Constants.CACHE_PURGE_EVENTBUS_ADDRESS, "");

        exchange.response()
                .setStatusCode(200)
                .putHeader("content-type", "application/json")
                .end();
    }

    // 其他路由方法按此格式修改
}

方案3:分离端口(不推荐)

如果必须保留手动创建的HttpServer,需修改Quarkus内置服务器的端口,避免冲突:
在application.properties中添加:

quarkus.http.port=8081

让你的自定义HttpServer继续监听8080,但这种方式会增加架构复杂度,违背Quarkus的整合设计理念。

内容的提问来源于stack exchange,提问作者Sascha Möllering

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.30 11:39:48