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

s.i*_*pma 15 java junit spring spring-mvc

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

@RequestMapping(value = "/get/image/{id}/{fileName}", method=RequestMethod.GET)
public @ResponseBody byte[] showImageOnId(@PathVariable("id") String id, @PathVariable("fileName") String fileName) {
    setContentType(fileName); //sets contenttype based on extention of file
    return getImage(id, fileName);
}
Run Code Online (Sandbox Code Playgroud)

以下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;
}
Run Code Online (Sandbox Code Playgroud)

我的JUnit测试完美无瑕

(编辑这是因为扩展.bla:这也适用于appserver):

@Test
public void testResourceNotFound() throws Exception {
    String fileName = "bla.bla";
      mvc.perform(MockMvcRequestBuilders.get("/get/image/bla/" + fileName)
            .with(httpBasic("test", "test")))
            .andDo(print())
            .andExpect(jsonPath("$error").value(Matchers.startsWith("Resource not found")))
            .andExpect(status().is(404));
}
Run Code Online (Sandbox Code Playgroud)

并给出以下输出:

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 = []
Run Code Online (Sandbox Code Playgroud)

但是在我的appserver上,我在尝试下载非现有图像时收到以下错误消息:

(编辑这是因为扩展.jpg:在使用.jpg扩展的JUnit测试中也失败了):

ERROR org.springframework.web.servlet.mvc.method.annotation.ExceptionHandlerExceptionResolver - Failed to invoke @ExceptionHandler method: public java.util.Map<java.lang.String, java.lang.String> nl.krocket.ocr.web.controller.ExceptionController.handleResourceNotFoundException(nl.krocket.ocr.web.backing.ResourceNotFoundException) org.springframework.web.HttpMediaTypeNotAcceptableException: Could not find acceptable representation

我在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;
}
Run Code Online (Sandbox Code Playgroud)

我错过了什么?为什么JUnit测试有效?

Ada*_*lik 30

您需要决定Spring应如何确定响应的媒体类型.这可以通过以下几种方式完成:

  • 路径扩展(例如/image.jpg)
  • URL参数(例如?格式= jpg)
  • HTTP Accept标头(例如,Accept:image/jpg)

默认情况下,Spring会查看扩展名而不是Accept标题.如果实现@Configuration扩展的类,则可以更改此行为WebMvcConfigurerAdapter.在那里,您可以WebMvcConfigurer根据需要覆盖和配置配置器,例如.通过电话

ContentNegotiationConfigurer#favorParameter
ContentNegotiationConfigurer#favorPathExtension
Run Code Online (Sandbox Code Playgroud)

如果将两者都设置为configureContentNegotiation(ContentNegotiationConfigurer configurer),则Spring将查看ContentNegotiationConfigurer标题.由于您的客户端可以说false和处理两者,Spring应该能够返回图像或错误JSON.

有关更多信息和示例,请参阅有关内容协商的Spring教程.

  • 感谢这个优秀的答案!最重要的是,我删除了消息转换器中支持的媒体类型的设置和控制器方法中内容类型的设置,因此所有内容都由 spring 协商。另外一个补充:要禁用路径变量截断,请在 webconfig 中使用 `matcher.setUseSuffixPatternMatch(false)`。 (2认同)