Java HttpMediaTypeNotAcceptableException:在exceptionhandler中找不到可接受的表示形式

Java HttpMediaTypeNotAcceptableException:在exceptionhandler中找不到可接受的表示形式,java,spring,spring-mvc,junit,Java,Spring,Spring Mvc,Junit,我的控制器(Spring 4.1)中有以下图像下载方法: 以下ControllerAdvice方法应处理不存在的文件并返回json错误响应: @ExceptionHandler(ResourceNotFoundException.class) @ResponseStatus(HttpStatus.NOT_FOUND) public @ResponseBody Map<String, String> handleResourceNotFoundException(ResourceNot

我的控制器(Spring 4.1)中有以下图像下载方法:

以下
ControllerAdvice
方法应处理不存在的文件并返回json错误响应:

@ExceptionHandler(ResourceNotFoundException.class)
@ResponseStatus(HttpStatus.NOT_FOUND)
public @ResponseBody Map<String, String> handleResourceNotFoundException(ResourceNotFoundException e) {
    Map<String, String> errorMap = new HashMap<String, String>();
    errorMap.put("error", e.getMessage());
    return errorMap;
}
并给出以下输出:

MockHttpServletResponse:
          Status = 404
   Error message = null
         Headers = {X-Content-Type-Options=[nosniff], X-XSS-Protection=[1; mode=block], Cache-Control=[no-cache, no-store, max-age=0, must-revalidate], Pragma=[no-cache], Expires=[0], X-Frame-Options=[DENY], Content-Type=[application/json]}
    Content type = application/json
            Body = {"error":"Resource not found: bla/bla.bla"}
   Forwarded URL = null
  Redirected URL = null
         Cookies = []
但是,在我的appserver上,我在尝试加载不存在的映像时收到以下错误消息:

EDIT这是因为extention.jpg:在使用.jpg extention的JUnit测试中也会失败):

ERROR org.springframework.web.servlet.mvc.method.annotation.ExceptionHandlerExceptionResolver-调用@ExceptionHandler方法失败:public java.util.Map nl.krocket.ocr.web.controller.ExceptionController.handleResourceNotFoundException(nl.krocket.ocr.web.backing.ResourceNotFoundException)
org.springframework.web.HttpMediaTypeNotAcceptableException:找不到可接受的表示形式

我在mvc配置中配置了messageconverters,如下所示:

@Override
public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
    converters.add(mappingJackson2HttpMessageConverter());
    converters.add(byteArrayHttpMessageConverter());
}

@Bean
public MappingJackson2HttpMessageConverter mappingJackson2HttpMessageConverter() {
    ObjectMapper objectMapper = new ObjectMapper();
    objectMapper.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS);
    objectMapper.setSerializationInclusion(JsonInclude.Include.NON_NULL);
    //objectMapper.registerModule(new JSR310Module());
    MappingJackson2HttpMessageConverter converter = new MappingJackson2HttpMessageConverter();
    converter.setObjectMapper(objectMapper);
    converter.setSupportedMediaTypes(getJsonMediaTypes());
    return converter;
}

@Bean
public ByteArrayHttpMessageConverter byteArrayHttpMessageConverter() {
    ByteArrayHttpMessageConverter arrayHttpMessageConverter = new ByteArrayHttpMessageConverter();
    arrayHttpMessageConverter.setSupportedMediaTypes(getImageMediaTypes());
    return arrayHttpMessageConverter;
}
@覆盖

public void configureMessageConverters(List您需要决定Spring应该如何确定响应的媒体类型。这可以通过几种方式完成:

  • 路径扩展(例如/image.jpg)
  • URL参数(例如?格式=jpg)
  • HTTP接受头(例如接受:image/jpg)
默认情况下,Spring查看的是扩展而不是
Accept
头。如果您实现了一个扩展的
@Configuration
类,则可以更改此行为(或者因为Spring 5.0只是实现了这个类)。在这里,您可以根据需要覆盖和配置,例如,通过调用

ContentNegotiationConfigurer#favorParameter
ContentNegotiationConfigurer#favorPathExtension
如果您将两者都设置为
false
,那么Spring将查看
Accept
标题。由于您的客户端可以说
Accept:image/*,application/json
,并同时处理这两个,因此Spring应该能够返回图像或错误json


有关更多信息和示例,请参见内容协商。

请注意HTTP Accept标头。 例如,如果控制器生成“应用程序/八位字节流”(响应中),则Accept标头不应为“应用程序/json”(请求中):


检查您的请求的“Accept”头(到appserver的“real”头)。它是否同时接受image/*和application/json?如果它只接受image/*则Spring无法生成json消息,因为它与请求所接受的内容不兼容。我有以下内容:接受:text/html、application/xhtml+xml、application/xml;q=0.9、image/webp、/;q=0.8如何更改?添加到MessageConverter(
setSupportedMediaTypes
)?当客户端需要图像时,接收JSON是否可能/有用?通常在请求图像时,错误响应代码就是客户端需要的所有信息(例如,在web应用程序中)。尝试调试引发异常的位置,可能是
AbstractMessageConverterMethodProcessor#writeWithMessageConverters()
RequestMappingInfoHandlerMapping#handleNoMatch
ServletHandlerMethodInvoker#WriteWithMessageConverter
我可以在ajax调用中处理404响应,以显示错误消息而不是图像,因此没有问题。错误是从
AbstractMessageConverterMethodProcessor.writeWithMessageConvert抛出的ers(AbstractMessageConverterMethodProcessor.java:134)
感谢您的出色回答!除此之外,我还删除了messageconverters中支持的MediaType的设置和控制器方法中contenttype的设置,因此所有内容都由spring协商。还有一个补充:要禁用pathvariable截断,请使用
matcher.setUseSuffixPatternMatch(false)
在webconfig中。您的答案很正确。改为1.9.2,效果很好。参考了大量与此问题相关的其他SO问题。其他都没有帮助。非常感谢您的澄清。这句话很准确——“默认情况下,Spring查看扩展名而不是Accept标头。”@Adam我想客户端在这种情况下会接受任何mime类型。请使用以下工具亲自尝试。在Spring Boot 2.2.2.RELEASE中使用
@GetMapping
时,我们如何在Spring Boot 2.2.RELEASE中执行此操作?@PAA我使用的是
@GetMapping
。我的答案是否与Spring Boot 2.2.2.RELEASE不兼容?
@Override
public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
    converters.add(mappingJackson2HttpMessageConverter());
    converters.add(byteArrayHttpMessageConverter());
}

@Bean
public MappingJackson2HttpMessageConverter mappingJackson2HttpMessageConverter() {
    ObjectMapper objectMapper = new ObjectMapper();
    objectMapper.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS);
    objectMapper.setSerializationInclusion(JsonInclude.Include.NON_NULL);
    //objectMapper.registerModule(new JSR310Module());
    MappingJackson2HttpMessageConverter converter = new MappingJackson2HttpMessageConverter();
    converter.setObjectMapper(objectMapper);
    converter.setSupportedMediaTypes(getJsonMediaTypes());
    return converter;
}

@Bean
public ByteArrayHttpMessageConverter byteArrayHttpMessageConverter() {
    ByteArrayHttpMessageConverter arrayHttpMessageConverter = new ByteArrayHttpMessageConverter();
    arrayHttpMessageConverter.setSupportedMediaTypes(getImageMediaTypes());
    return arrayHttpMessageConverter;
}
ContentNegotiationConfigurer#favorParameter
ContentNegotiationConfigurer#favorPathExtension
@GetMapping(value = "/download", produces = MediaType.APPLICATION_OCTET_STREAM_VALUE)
public void download(HttpServletResponse response) {}