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

Quarkus空闲超时返回500而非408,如何用ExceptionMapper自定义响应?

解决Quarkus空闲超时无法捕获并返回自定义响应的问题

原因分析

quarkus.http.idle-timeout是由Quarkus底层Servlet容器(默认是Undertow)处理的超时逻辑,触发该超时的时候,请求已经脱离了JAX-RS的处理上下文,所以你定义的ExceptionMapper无法捕获到对应的异常,容器会直接返回500状态码。

解决方案

1. 基于Undertow容器自定义超时处理

如果你的Quarkus使用默认的Undertow容器,可以通过自定义Undertow Handler来拦截超时事件并返回自定义响应:

  • 先创建自定义超时Handler类:
import io.undertow.server.HttpHandler;
import io.undertow.server.HttpServerExchange;
import io.undertow.util.StatusCodes;

public class CustomTimeoutHandler implements HttpHandler {
    private final HttpHandler next;

    public CustomTimeoutHandler(HttpHandler next) {
        this.next = next;
    }

    @Override
    public void handleRequest(HttpServerExchange exchange) throws Exception {
        // 绑定超时回调逻辑
        exchange.addTimeoutListener(exchange1 -> {
            if (!exchange1.isResponseStarted()) {
                exchange1.setStatusCode(StatusCodes.REQUEST_TIMEOUT);
                exchange1.getResponseSender().send("请求超时,请稍后重试");
            }
        });
        next.handleRequest(exchange);
    }
}
  • 再创建扩展类将Handler注册到Undertow中:
import io.quarkus.undertow.runtime.UndertowDeploymentInfoCustomizer;
import io.undertow.servlet.api.DeploymentInfo;
import jakarta.enterprise.context.ApplicationScoped;

@ApplicationScoped
public class UndertowCustomizer implements UndertowDeploymentInfoCustomizer {
    @Override
    public void customize(DeploymentInfo deploymentInfo) {
        deploymentInfo.addInitialHandlerChainWrapper(next -> new CustomTimeoutHandler(next));
    }
}

2. 改用JAX-RS层面的超时配置

如果业务场景允许,可以放弃容器级的idle-timeout,改用JAX-RS层面的超时配置,这样超时异常会进入JAX-RS上下文,就能被ExceptionMapper捕获:

  • 全局配置JAX-RS超时(在application.properties中):
quarkus.rest-client.connect-timeout=15S
quarkus.rest-client.read-timeout=15S

也可以针对特定端点使用@Timeout注解单独配置超时时间。

  • 修改ExceptionMapper捕获对应超时异常:
@Provider
public class TimeoutExceptionHandler implements ExceptionMapper<ProcessingException> {

    private static final ShareLogger LOGGER = ShareLogger.create(TimeoutExceptionHandler.class);

    @Override
    public Response toResponse(final ProcessingException e) {
        if (e.getCause() instanceof SocketTimeoutException) {
            LOGGER.debug("请求超时异常: {}", e.toString());
            return Response.status(Response.Status.REQUEST_TIMEOUT)
                    .entity("请求超时")
                    .build();
        }
        return Response.serverError().entity("服务器错误").build();
    }
}

3. 简单配置错误响应映射

如果只需要修改状态码和简单响应内容,可以直接在application.properties中配置:

# 将原500状态码替换为408
quarkus.http.error.status-code.500=408
# 自定义408响应消息
quarkus.http.error.message.408=您的请求已超时,请稍后重试

内容的提问来源于stack exchange,提问作者StevethecheeF

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.16 18:31:17