Spring允许在@ExceptionHandlers
内定义@RestControllerAdvice
。
我已经在那里为HTTP 400,404,405定义了很多其他ExceptionHandlers
......但是HTTP 406的ExceptionHandler(NOT_ACCEPTABLE)似乎不起作用。处理程序被触发,我在日志中检查了它,但结果未被使用。
我的目标是返回带有JSON主体的HTTP 406。
变体1
@ResponseStatus(HttpStatus.NOT_ACCEPTABLE)
@ExceptionHandler(HttpMediaTypeNotAcceptableException.class)
public ErrorDTO requestMethodNotSupported(final HttpMediaTypeNotAcceptableException e) {
final ErrorDTO dto = new ErrorDTO(HttpStatus.NOT_ACCEPTABLE, "http.media_not_acceptable");
return dto;
}
变体2
@ExceptionHandler(HttpMediaTypeNotAcceptableException.class)
public ResponseEntity<ErrorDTO> requestMethodNotSupported2(final HttpMediaTypeNotAcceptableException e) {
final ErrorDTO dto = new ErrorDTO(HttpStatus.NOT_ACCEPTABLE, "http.media_not_acceptable");
return ResponseEntity.status(HttpStatus.NOT_ACCEPTABLE).contentType(MediaType.APPLICATION_JSON_UTF8).body(dto);
}
但我总是从Tomcat获得与此类似的HTML响应:
HTTP状态406 -
类型:状态报告
消息:
description:标识的资源 此请求只能生成响应 根据要求不可接受的特征&#34;接受&#34; 头。
而不是
{ &#34; errorCode&#34;:406, &#34; errorMessage&#34;:&#34; http.media_not_acceptable&#34; }
请求报头:
实际 - 响应 - 接头
预期 - 响应 - 接头
我知道我可以简单地修复&#34;客户端发送的Accept-Header,但是如果服务器不知道如何响应,则应始终以JSON响应。
我使用Spring 4.3.3.RELEASE和Jackson 2.8.4。
答案 0 :(得分:6)
最后我找到了解决方案:
不是返回可序列化对象,而是直接返回字节。
private final ObjectMapper objectMapper = new ObjectMapper();
@ExceptionHandler(HttpMediaTypeNotAcceptableException.class)
public ResponseEntity<byte[]> requestMethodNotSupported(HttpMediaTypeNotAcceptableException e) {
Object response = ...;
try {
return ResponseEntity.status(HttpStatus.NOT_ACCEPTABLE)
.contentType(MediaType.APPLICATION_JSON_UTF8)
.body(objectMapper.writeValueAsBytes(response));
} catch (Exception subException) {
// Should never happen!!!
subException.addSuppressed(e);
throw subException;
}
}
修改强>
作为替代方案,您可以为HttpMessageConverter<ErrorResponse>
对象创建自定义ErrorResponse
。
WebMvcConfigurerAdapter#extendMessageConverters(converters)
HttpMessageConverter
。getSupportedMediaTypes()
返回MediaType.ALL
canRead()
返回false canWrite()
仅对您的ErrorResponse
write()
设置强制CT并将您预期的内容类型转发到包装转换器。答案 1 :(得分:1)
以@ST-DDT 调查结果为基础。如果您还扩展了 ResponseEntityExceptionHandler
,那么您不能只添加另一个方法来处理 HttpMediaTypeNotAcceptableException
。但是,对于整个问题,还有一个更简单的解决方案:
@Override
public ResponseEntity<Object> handleHttpMediaTypeNotAcceptable(HttpMediaTypeNotAcceptableException ex, HttpHeaders headers, HttpStatus status, WebRequest request) {
ResponseEntity<Object> response = super.handleHttpMediaTypeNotAcceptable(ex, headers, status, request);
// Workaround to return JSON response for 406
return ResponseEntity.status(NOT_ACCEPTABLE)
.contentType(APPLICATION_JSON)
.body(response.getBody());
}