Quarkus集成RestEasy调用接口报错时无法获取响应体如何解决?
问题根因
Quarkus集成的RestEasy Rest客户端默认处理4xx/5xx错误响应时,会直接抛出WebApplicationException,直接调用该异常的getEntity()方法无法获取响应体,响应实体实际存储在异常携带的Response对象中;另外如果配置了客户端日志过滤器消费了响应流、或者没有开启响应实体缓冲,也会导致读取响应体为空。
注意事项
首先在application.properties中添加如下配置,避免响应流被提前消费后无法读取:
quarkus.rest-client.buffer-response-entity=true
解决方案
方案1:直接从异常携带的Response中读取
捕获WebApplicationException后先获取响应对象再读取实体,示例代码如下:
try { myService.create(request); } catch (WebApplicationException e) { try (Response response = e.getResponse()) { // 直接读取为字符串 String errorBody = response.readEntity(String.class); // 也可以直接反序列化为自定义错误实体类 ErrorResp error = response.readEntity(ErrorResp.class); // 后续错误处理逻辑 } }
方案2:自定义异常映射器统一处理错误
实现ResponseExceptionMapper接口,将错误响应直接转换为自定义业务异常,避免每次调用手动捕获处理:
- 定义错误响应实体类和自定义业务异常
// 错误响应对应实体类 public class ErrorResponse { private ErrorInfo error; // 补充getter、setter方法 public static class ErrorInfo { private String id; // 补充getter、setter方法 } } // 自定义业务异常 public class BusinessException extends RuntimeException { private final ErrorResponse errorResponse; public BusinessException(ErrorResponse errorResponse) { this.errorResponse = errorResponse; } public ErrorResponse getErrorResponse() { return errorResponse; } }
- 实现异常映射器
@Provider public class BusinessExceptionMapper implements ResponseExceptionMapper<RuntimeException> { @Override public RuntimeException toThrowable(Response response) { // 可根据需求调整需要处理的状态码范围 if (response.getStatus() >= 400 && response.getStatus() < 500) { ErrorResponse error = response.readEntity(ErrorResponse.class); return new BusinessException(error); } // 返回null走默认异常处理逻辑 return null; } }
- 在Rest Client接口上注册映射器
@Path("/") @RegisterRestClient @RegisterProvider(value = ClientLoggingFilter.class, priority = 100) @RegisterProvider(BusinessExceptionMapper.class) // 新增注册自定义映射器 public interface MyService { @POST @Path("/foo") @Consumes(MediaType.APPLICATION_JSON) MyResponse create(MyRequest request); }
配置完成后调用接口遇到对应状态码会直接抛出BusinessException,可直接从异常中获取结构化的错误信息。
方案3:关闭自动异常抛出自行处理所有响应
将Rest Client方法返回值改为Response,客户端不会自动抛出异常,可自行判断状态码处理逻辑:
@Path("/") @RegisterRestClient @RegisterProvider(value = ClientLoggingFilter.class, priority = 100) public interface MyService { @POST @Path("/foo") @Consumes(MediaType.APPLICATION_JSON) Response create(MyRequest request); // 返回值改为Response }
调用示例:
try (Response response = myService.create(request)) { if (response.getStatus() == Response.Status.OK.getStatusCode()) { MyResponse resp = response.readEntity(MyResponse.class); // 处理正常响应逻辑 } else if (response.getStatus() == Response.Status.BAD_REQUEST.getStatusCode()) { ErrorResponse error = response.readEntity(ErrorResponse.class); // 处理错误响应逻辑 } }
内容的提问来源于stack exchange,提问作者Nitro Blade
相关产品推荐
相关产品推荐

