Java 根据@ExceptionHandler响应内容类型的Spring HttpMessageConverter
我有一个基于SpringMVC的RESTWeb服务。我使用Java 根据@ExceptionHandler响应内容类型的Spring HttpMessageConverter,java,spring,spring-mvc,spring-boot,exceptionhandler,Java,Spring,Spring Mvc,Spring Boot,Exceptionhandler,我有一个基于SpringMVC的RESTWeb服务。我使用@RestControllerAdvice来处理从我的@Controller抛出的异常 控制器 调用的示例如下所示 @GetMapping(value = "/{id}/{name:.+}", produces = { MediaType.APPLICATION_OCTET_STREAM_VALUE, MediaType.APPLICATION_XML_VALUE, MediaType.APPLICATION_JSON_
@RestControllerAdvice
来处理从我的@Controller
抛出的异常
控制器 调用的示例如下所示
@GetMapping(value = "/{id}/{name:.+}", produces = { MediaType.APPLICATION_OCTET_STREAM_VALUE,
MediaType.APPLICATION_XML_VALUE, MediaType.APPLICATION_JSON_VALUE })
ResponseEntity<byte[]> getSomething(
@PathVariable("id") String id, @PathVariable("name") String name) throws customException;
根据请求接受标头,@ExceptionHandler
返回空正文,如果未设置接受,则返回不可接受的http响应状态,或者,如果accept的类型为APPLICATION\u JSON
,则类型为ErrorDto
的对象属于APPLICATION\u XML
请注意,我在响应时指定了响应的内容类型
包含一个主体
问题
我的问题是,当客户端使用多个accept头进行调用时,Spring会尝试根据accept头而不是响应内容类型拾取HttpMessageConverter
。下面是一个例子:
当客户端调用一个抛出异常(然后返回errorDto)的方法时,该方法具有多个Accept标头,如下所示:
HttpHeaders headers = new HttpHeaders();
headers.add(HttpHeaders.ACCEPT, MediaType.APPLICATION_OCTET_STREAM_VALUE);
headers.add(HttpHeaders.ACCEPT, MediaType.APPLICATION_XML_VALUE);
HttpEntity<?> entity = new HttpEntity<>(body, headers);
restTemplate.exchange(uriComponents.encode().toUri(), httpMethod, entity, Class);
HttpHeaders=newhttpheaders();
headers.add(HttpHeaders.ACCEPT,MediaType.APPLICATION\u OCTET\u STREAM\u VALUE);
headers.add(HttpHeaders.ACCEPT,MediaType.APPLICATION\u XML\u VALUE);
HttpEntity实体=新的HttpEntity(主体、标题);
restemplate.exchange(uriComponents.encode().tori(),httpMethod,entity,Class);
Spring不会像预期的那样返回XML格式错误的响应。它查找不存在且不尝试根据响应内容类型查找转换器的Octet-Stream-JaxbElement
转换器
如何根据响应内容类型强制Spring使用转换器?
我正在使用:
- 弹簧靴1.4.0.释放
弹簧有这个错误。根据:
根据我的经验,REST服务的错误处理是其中一种情况,在这种情况下,最好强制响应简单的内容,如文本/纯文本,以便向客户机发送有意义的错误消息
Spring在这里过于固执己见的行为掩盖了406响应中出现的主要错误。因此,上述RFC注释同样适用于所有4xx和5xx响应。如果您无法匹配接受的内容类型,那么您可能不应该发送1xx、2xx或3xx范围内的任何响应。“我的问题是,当客户端使用多个接受标头进行呼叫时,Spring会尝试根据接受标头而不是响应内容类型来选择HttpMessageConverter”这不是问题,HTTP就是这样工作的。您不能发送客户不理解的内容。事实上,在我的示例中,客户理解它在accept中发送的内容。在上面的示例中,客户机理解八位字节流和xml。我想用xml而不是八位字节流向他发送一个错误。但是由于八位字节流被放在头中的第一位,Spring试图获取八位字节流httpMessageConverter。我理解。然后,
handleException
方法中可能有错误。我试着调试spring源mvc代码以了解spring如何处理这个问题,所有的魔法都是在方法AbstractMessageConverterMethodProcessor#writeWithMessageConverters
中完成的。不幸的是,正如预期的那样,Spring根据请求的MediaTypes而不是响应MediaType选择HttpMessageConverter。如果您可以控制客户端,则可以为MediaType.APPLICATION\u OCTET\u STREAM\u value
指定较低质量的值。
HttpHeaders headers = new HttpHeaders();
headers.add(HttpHeaders.ACCEPT, MediaType.APPLICATION_OCTET_STREAM_VALUE);
headers.add(HttpHeaders.ACCEPT, MediaType.APPLICATION_XML_VALUE);
HttpEntity<?> entity = new HttpEntity<>(body, headers);
restTemplate.exchange(uriComponents.encode().toUri(), httpMethod, entity, Class);
Note: HTTP/1.1 servers are allowed to return responses which are
not acceptable according to the accept headers sent in the
request. In some cases, this may even be preferable to sending a
406 response. User agents are encouraged to inspect the headers of
an incoming response to determine if it is acceptable.