Quarkus Reactive Rest如何抛出NotFoundException返回404响应
原因说明
在CompletionStage的thenApply异步回调中直接抛出的NotFoundException,会被异步计算逻辑包装为嵌套异常,Quarkus RESTEasy Reactive默认的异常处理器无法直接识别这类嵌套在异步链中的404异常,会将其判定为未捕获的服务端异常,最终返回500状态码并打印错误日志。
实现方案
方案1:调整异步链返回逻辑(推荐,无额外配置)
不要在thenApply中直接抛出异常,改用thenCompose处理异步结果:当查询到Account时返回包装了Account对象的成功Future,当Account不存在时,显式返回携带NotFoundException的失败Future。这种方式抛出的异常不会被额外嵌套包装,框架可以直接识别并自动返回404响应,不会打印ERROR级别的异常栈。
@GET @Path("/{id}") public CompletionStage<Account> get(@PathParam("id") String id) { return accountProvider .get(id) .thenCompose(maybeAccount -> maybeAccount .map(CompletableFuture::completedFuture) .orElseGet(() -> CompletableFuture.failedFuture(new NotFoundException())) ); }
方案2:自定义异步异常映射器(适合批量处理同类场景)
如果项目中存在大量同类异步接口,可以注册全局异常处理器,解包异步链抛出的CompletionException,识别其中嵌套的NotFoundException并返回404响应:
import jakarta.ws.rs.NotFoundException; import jakarta.ws.rs.core.Response; import jakarta.ws.rs.ext.ExceptionMapper; import jakarta.ws.rs.ext.Provider; import java.util.concurrent.CompletionException; @Provider public class AsyncExceptionMapper implements ExceptionMapper<CompletionException> { @Override public Response toResponse(CompletionException e) { Throwable rootCause = e.getCause(); if (rootCause instanceof NotFoundException) { return Response.status(Response.Status.NOT_FOUND).build(); } // 其余异常交由框架默认异常处理器处理 throw new RuntimeException(rootCause); } }
注意:请确保代码中使用的
NotFoundException是jakarta.ws.rs.NotFoundException(Quarkus 3.x版本基于Jakarta EE,包名前缀为jakarta;Quarkus 2.x版本对应包名为javax.ws.rs.NotFoundException),引入错包下的同名异常也会导致框架无法识别。
内容的提问来源于stack exchange,提问作者sam
相关产品推荐
相关产品推荐

