[英]Spring return JSON for HTTP 406 (NOT_ACCEPTABLE)
Spring 允许在@ExceptionHandlers
内部定义@RestControllerAdvice
。
我已经在那里为 HTTP 400、404、405 定义了很多其他的ExceptionHandlers
,...但是 HTTP 406(NOT_ACCEPTABLE)的 ExceptionHandler 似乎不起作用。 处理程序被触发,我在日志中检查过,但没有使用结果。
我的目标是返回一个带有 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 -
类型:状态报告
消息:
描述:此请求标识的资源只能生成具有根据请求“接受”标头不可接受的特征的响应。
而不是
{ "errorCode": 406, "errorMessage": "http.media_not_acceptable" }
请求头:
实际响应头:
预期响应头:
我知道我可以简单地“修复”客户端发送的 Accept-Header,但是如果服务器不知道如何响应,它应该始终以 JSON 响应。
我使用 Spring 4.3.3.RELEASE 和 Jackson 2.8.4。
最后我找到了一个解决方案:
直接返回字节而不是返回可序列化的对象。
private final ObjectMapper objectMapper = new ObjectMapper();
@ExceptionHandler(HttpMediaTypeNotAcceptableException.class)
public ResponseEntity<byte[]> mediaTypeNotAcceptable(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;
}
}
编辑:
作为替代方案,您可以为ErrorResponse
对象创建自定义HttpMessageConverter<ErrorResponse>
。
WebMvcConfigurerAdapter#extendMessageConverters(converters)
HttpMessageConverter
。getSupportedMediaTypes()
返回MediaType.ALL
canRead()
返回 falsecanWrite()
只为您的ErrorResponse
返回 truewrite()
设置强制 CT 并将您预期的内容类型转发到包装的转换器。基于@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());
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.