如何在Micronaut的@Body注解中捕获错误并抛出结构化异常
在Micronaut中捕获并格式化@Body绑定失败的异常
针对你遇到的问题——当@Body无法创建请求对象时无法捕获异常并返回标准化格式,分两种场景给出解决方案:
服务端场景:捕获请求体解析失败的异常
当客户端发送的请求体无法被反序列化为控制器方法的@Body参数时,Micronaut会抛出HttpMessageConversionException,这个异常不会被控制器内的try-catch或普通@Error注解捕获,因为请求还未进入控制器逻辑。你需要实现全局异常处理器来处理它:
import io.micronaut.context.annotation.Requires; import io.micronaut.http.HttpRequest; import io.micronaut.http.HttpResponse; import io.micronaut.http.annotation.Produces; import io.micronaut.http.server.exceptions.ExceptionHandler; import jakarta.inject.Singleton; @Produces @Singleton @Requires(classes = {HttpMessageConversionException.class, ExceptionHandler.class}) public class RequestBodyParseExceptionHandler implements ExceptionHandler<HttpMessageConversionException, HttpResponse<StandardizedError>> { @Override public HttpResponse<StandardizedError> handle(HttpRequest request, HttpMessageConversionException exception) { StandardizedError error = new StandardizedError(); error.setCode("REQUEST_BODY_PARSE_FAILED"); error.setMessage("请求体格式无效,无法解析为目标对象"); error.setDetails(exception.getCause().getMessage()); return HttpResponse.badRequest().body(error); } // 自定义标准化异常响应类 public static class StandardizedError { private String code; private String message; private String details; // 此处添加getter和setter方法 } }
这个处理器会全局捕获所有请求体解析失败的异常,返回你定义的标准化响应格式。
客户端场景:捕获HttpClientResponseException
如果你的应用作为客户端调用外部服务,因请求体序列化失败或对方返回错误导致抛出HttpClientResponseException,可以通过两种方式处理:
方式1:局部try-catch捕获
在客户端调用代码中直接捕获异常并格式化:
try { HttpResponse<YourResponse> response = httpClient.toBlocking().exchange( HttpRequest.POST("/external/api", yourRequestBody), YourResponse.class ); } catch (HttpClientResponseException e) { StandardizedError error = new StandardizedError(); error.setCode("CLIENT_REQUEST_ERROR"); error.setMessage("调用外部服务失败"); error.setDetails(e.getResponse().getBody(String.class).orElse("无详细错误信息")); // 此处处理或返回标准化异常 }
方式2:全局ErrorDecoder处理
实现全局的ErrorDecoder来统一解析客户端异常:
import io.micronaut.http.HttpResponse; import io.micronaut.http.client.exceptions.HttpClientResponseException; import io.micronaut.http.codec.ErrorDecoder; import jakarta.inject.Singleton; @Singleton public class CustomClientErrorDecoder implements ErrorDecoder { @Override public Exception decode(String url, HttpResponse<?> response) { StandardizedError error = response.getBody(StandardizedError.class).orElse(null); if (error != null) { return new CustomClientException(error); } return new HttpClientResponseException("客户端请求失败", response); } // 自定义携带标准化错误的异常类 public static class CustomClientException extends RuntimeException { private final StandardizedError error; public CustomClientException(StandardizedError error) { super(error.getMessage()); this.error = error; } public StandardizedError getError() { return error; } } }
之后你可以在调用处捕获CustomClientException,直接获取标准化的错误信息。
内容的提问来源于stack exchange,提问作者Nick Jones
相关产品推荐
相关产品推荐

