Java 根据@ExceptionHandler响应内容类型的Spring HttpMessageConverter

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_

我有一个基于SpringMVC的RESTWeb服务。我使用
@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.