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
相关产品推荐
相关产品推荐

