我有一个基于 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_VALUE
,APPLICATION_XML_VALUE
和APPLICATION_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;
};
转换器,并且不会根据响应内容类型尝试查找转换器。
我正在使用: