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

时间:2017-01-24 12:01:39

标签: java spring spring-mvc spring-boot exceptionhandler

我有一个基于 Spring MVC 的Rest Web服务。我使用@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;

可以生成3种媒体类型的基本方法:APPLICATION_OCTET_STREAM_VALUEAPPLICATION_XML_VALUEAPPLICATION_JSON_VALUE并抛出customException

异常处理程序

@RestControllerAdvice的定义如下:

@ExceptionHandler({ CustomException.class })
public ResponseEntity<Object> handleException(CustomException e) {

    ErrorDto err = errorMapper.map(e);
    Enumeration<String> en = httpServletRequest.getHeaders(HttpHeaders.ACCEPT);

    while (en.hasMoreElements()) {
        String list = en.nextElement();
        StringTokenizer st = new StringTokenizer(list, ",");

        while (st.hasMoreTokens()) {

            String acc = st.nextToken();
            MediaType contentTypeHeader = MediaType.valueOf(acc);

            if (MediaType.APPLICATION_XML.includes(contentTypeHeader)) {

                JAXBElement<ErrorDto> ret = new ObjectFactory().createError(err);
                return ResponseEntity.status(HttpStatus.PRECONDITION_FAILED)
                        .contentType(MediaType.APPLICATION_XML).body(ret);

            } else if (MediaType.APPLICATION_JSON.includes(contentTypeHeader)) {

                return ResponseEntity.status(HttpStatus.PRECONDITION_FAILED)
                        .contentType(MediaType.APPLICATION_JSON).body(err);

            }
        }
    }

    return ResponseEntity.status(HttpStatus.NOT_ACCEPTABLE).body(null);
}

根据请求接受标头,如果未设置接受,则@ExceptionHandler将返回空主体和NOT_ACCEPTABLE http响应状态,如果设置为ErrorDto,则返回APPLICATION_JSON的对象接受属于JaxbElement类型或ErrorDto属于APPLICATION_XML,接受类型为HttpMessageConverter

  

请注意,我指定响应的内容类型   包含一个身体。

问题

我的问题是当客户端使用多个接受标头进行调用时,Spring会尝试根据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); 。下面是一个例子:

当客户端调用抛出异常的方法(然后返回errorDto)时,多个Accept标头如下所示:

Octet-Stream <-> JaxbElement

Spring不会按预期返回XML格式错误的响应。它会查找不存在的struct MYTREE { struct MYTREE *left, *right; union { char *charval; int intval; } value; }; 转换器,并且不会根据响应内容类型尝试查找转换器。

如何根据响应内容类型强制Spring使用转换器?

我正在使用:

  • Spring Boot 1.4.0.RELEASE

0 个答案:

没有答案