我有一个 Spring RequestMapping,它采用 JSON 结构并将其转换为 POJO。如果我向路由发送格式错误的 JSON 结构,我会收到“400 错误请求”,但我希望收到一条错误消息,说明为什么这是错误请求。我有一个验证器也检查 JSON 结构,但如果结构无法转换,它似乎不会被调用。有没有办法可以访问内置的 HttpMessageConverter 错误或异常?
我认为您可以通过重写 handleHttpMessageNotReadable
方法来使用
ResponseEntityExceptionHandler来实现此目的。
来自:17.11.3 处理标准 Spring MVC 异常:
如果您更喜欢通过 @ExceptionHandler 方法编写错误内容,您可以扩展 ResponseEntityExceptionHandler 。这是 @ControllerAdvice 类的便捷基础,提供 @ExceptionHandler 方法来处理标准 Spring MVC 异常并返回 ResponseEntity。这允许您自定义响应并使用消息转换器编写错误内容。有关更多详细信息,请参阅 ResponseEntityExceptionHandler javadocs。
可以在此处找到
ResponseEntityExceptionHandler
的示例用法:http://www.jayway.com/2013/02/03/improve-your-spring-rest-api-part-iii/
否则你可以在这里找到更多 spring mvc 异常处理方法: https://spring.io/blog/2013/11/01/exception-handling-in-spring-mvc
如果您的需求不太复杂,您可能只想使用 SimpleMappingExceptionResolver
ResponseEntityExceptionHandler 用于识别 Spring MVC 特定异常并为它们实现常见的错误响应处理策略。
它由许多方法组成,例如:
下面提到的代码覆盖了 handleExceptionInternal 方法
@ControllerAdvice
public class JavaWebExeptionHandler extends ResponseEntityExceptionHandler {
public class ExpnDetails {
public int expnCode;
public String expnMessage;
}
// A single place to customize the response body of all exception types.
@Override
protected ResponseEntity<ExpnDetails> handleExceptionInternal(Exception ex, Object body,
HttpHeaders headers,HttpStatus status, WebRequest request) {
return new ResponseEntity<Object>(new ExpnDetails(status.value(), ex.getMessage()), status);
}
}
因此,所有 Spring MVC 特定异常都在一个地方处理,并且 ExpnDetails 对象作为响应 body 发送,其中包含 expnCode 和 expnMessage。
输出:
{
"expnCode": 415,
"expnMessage": "Content type 'application/json1' not supported"
}
{
"expnCode": 400,
"expnMessage": "JSON parse error: Unexpected character ('"
' (code 34)): was expecting comma to separate Object entries; nested exception is com.fasterxml.jackson.core.JsonParseException: Unexpected character ('
"' (code 34)): was expecting comma to separate Object entries at [Source: (PushbackInputStream); line: 3, column: 4]"
}
注意此解决方案还有助于隐藏容器(例如tomcat服务器)详细信息,以便在请求失败时出现在响应错误中。
如果您不想使用任何自定义类,而只想区分特定情况(例如无效的 json),您可以使用类似以下内容:
@Order(Ordered.HIGHEST_PRECEDENCE)
@ControllerAdvice
public class RestExceptionHandler extends ResponseEntityExceptionHandler {
@Override
protected ResponseEntity<Object> handleHttpMessageNotReadable(HttpMessageNotReadableException ex, HttpHeaders headers,
HttpStatusCode status, WebRequest request) {
String defaultDetail = (ex.getMessage() != null && ex.getMessage().contains("JSON parse error"))
? "Invalid JSON Request"
: "Failed to read request";
ProblemDetail body = createProblemDetail(ex, status, defaultDetail, null, null, request);
return handleExceptionInternal(ex, body, headers, status, request);
}
}
这里我们使用与默认实现类似的实现,但只是将消息调整为特定于实际问题。您还可以直接使用 ex.getMessage 并传递它(如果您可以将整个详细信息公开给客户端),否则您可以构建自定义逻辑以按照上面所示的方式转换特定错误。
因此,在上面的代码中,如果由于 JSON 格式问题导致正文根本不可读,我们将得到正确的响应。