问题描述
Spring允许在 @RestControllerAdvice
内定义 @ExceptionHandlers
。
我已经在那里为HTTP 400、404、405等定义了许多其他 ExceptionHandlers
...但是HTTP 406的ExceptionHandler(NOT_ACCEPTABLE)确实可以似乎不起作用。
我的目标是返回带有JSON正文的HTTP 406。
p>
变体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)
返回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响应:
而不是
请求标头:
接受:应用程序/无法显示的东西
实际响应标题:
内容类型:text / html
预期响应标头:
Content-Type:application / json
我知道我可以简单地修复由客户端,但是如果服务器不知道如何响应,服务器应该始终以JSON响应。
我使用Spring 4.3.3.RELEASE和Jackson 2.8.4。 / p>
最后,我找到了解决方案:
而不是返回
private final ObjectMapper objectMapper = new ObjectMapper();
@ExceptionHandler(HttpMediaTypeNotAcceptableException.class)
public ResponseEntity< byte []> requestMethodNotSupported(HttpMediaTypeNotAcceptableException e){
对象响应= ...;
try {
return ResponseEntity.status(HttpStatus.NOT_ACCEPTABLE)
.contentType(MediaType.APPLICATION_JSON_UTF8)
.body(objectMapper.writeValueAsBytes(response));
} catch(Exception subException){
//不应该发生!!!
subException.addSuppressed(e);
throw subException;
}
}
编辑:
作为替代方案,您可以为 ErrorResponse $创建自定义
HttpMessageConverter< ErrorResponse>
c $ c>对象。
转到您的目录或创建一个
WebMvcConfigurerAdapter#extendMessageConverters(converters) code>
选择一个能够创建预期结果/内容类型的 HttpMessageConverter
。
将其包装为满足以下条件的方式:
getSupportedMediaTypes()
返回 MediaType.ALL
canRead()
返回false
canWrite()
仅对您的 ErrorResponse
返回true write()
设置强制CT并将您期望的内容类型转发给包装的转换器。
将包装器添加到转换器列表。
如果添加为第一个元素,它将始终返回您的预期结果(强制)
请求:json,返回:强制CT
请求:xml,返回:强制CT
请求:image,返回:强制CT
如果添加为最后一个元素,则如果没有其他匹配的转换器(备用)$ b,它将仅返回预期结果
$ b
请求:json,返回:json
请求:xml,返回:xml
请求:图像,返回:强制CT
Spring allows the definition of @ExceptionHandlers
inside of @RestControllerAdvice
.
I already defined a lot of other ExceptionHandlers
in there for HTTP 400, 404, 405,... However the ExceptionHandler for HTTP 406 (NOT_ACCEPTABLE) does not seem to work. The handler is triggered, I checked that in the logs, but the result is not used.
My goal is it to return a HTTP 406 with a JSON body.
Variant 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;
}
Variant 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);
}
But I always get a HTML response similar to this from the Tomcat:
instead of
Request-Headers:
- Accept: application/stuff-that-cannot-be-present
Actual-Response-Headers:
- Content-Type: text/html
Expected-Response-Headers:
- Content-Type: application/json
I know that I could simply "fix" the Accept-Header that is send by the client, however the server should always respond in JSON, if it does not know how to respond.
I use Spring 4.3.3.RELEASE and Jackson 2.8.4.
Finally I found a solution for this:
Instead of returning a serializable object just return the bytes directly.
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;
}
}
EDIT:
As an alternative you can create a custom HttpMessageConverter<ErrorResponse>
for your ErrorResponse
object.
- Go to your or create a impl of
WebMvcConfigurerAdapter#extendMessageConverters(converters)
Pick a HttpMessageConverter
that is capable of creating your expected result/content type.Wrap it in a way to fulfill the following conditions:getSupportedMediaTypes()
returns MediaType.ALL
canRead()
returns false canWrite()
returns only true for your ErrorResponse
write()
sets the forced CT and forward your expected content type to the wrapped converter.- If added as first element then it will always return your expected result (forced)
- Requested: json , Returned: forced CTRequested: xml , Returned: forced CTRequested: image , Returned: forced CT
- Requested: json , Returned: jsonRequested: xml , Returned: xmlRequested: image , Returned: forced CT
这篇关于Spring返回HTTP 406的JSON(NOT_ACCEPTABLE)的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!