Java HttpMediaTypeNotAcceptableException:在异常处理程序中找不到可接受的表示
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/32351142/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
HttpMediaTypeNotAcceptableException: Could not find acceptable representation in exceptionhandler
提问by s.ijpma
I have the following image download method in my controller (Spring 4.1):
我的控制器(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);
}
The following ControllerAdvice
method should handle a non-existing file and return a json error response:
以下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;
}
My JUnit test works flawless
我的 JUnit 测试完美无缺
(EDITthis is because of extention .bla : this also works on appserver):
(编辑这是因为扩展 .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));
}
and gives the following output:
并给出以下输出:
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 = []
However on my appserver i get the following error message when trying to donwload non existing image:
但是,在我的应用服务器上,尝试下载不存在的图像时收到以下错误消息:
(EDITthis is because of extention .jpg : this also fails on JUnit test with .jpg extention):
(编辑这是因为扩展名 .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
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
I have configured messageconverters in my mvc configuration as follows:
我在我的 mvc 配置中配置了 messageconverters 如下:
@Override
public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
converters.add(mappingHymanson2HttpMessageConverter());
converters.add(byteArrayHttpMessageConverter());
}
@Bean
public MappingHymanson2HttpMessageConverter mappingHymanson2HttpMessageConverter() {
ObjectMapper objectMapper = new ObjectMapper();
objectMapper.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS);
objectMapper.setSerializationInclusion(JsonInclude.Include.NON_NULL);
//objectMapper.registerModule(new JSR310Module());
MappingHymanson2HttpMessageConverter converter = new MappingHymanson2HttpMessageConverter();
converter.setObjectMapper(objectMapper);
converter.setSupportedMediaTypes(getJsonMediaTypes());
return converter;
}
@Bean
public ByteArrayHttpMessageConverter byteArrayHttpMessageConverter() {
ByteArrayHttpMessageConverter arrayHttpMessageConverter = new ByteArrayHttpMessageConverter();
arrayHttpMessageConverter.setSupportedMediaTypes(getImageMediaTypes());
return arrayHttpMessageConverter;
}
What am i missing? And why is the JUnit test working?
我错过了什么?为什么 JUnit 测试有效?
采纳答案by Adam Michalik
You need to decide how the media type of the response should be determined by Spring. That can be done in several ways:
您需要决定 Spring 应如何确定响应的媒体类型。这可以通过多种方式完成:
- path extension (eg. /image.jpg)
- URL parameter (eg. ?format=jpg)
- HTTP Accept header (eg. Accept: image/jpg)
- 路径扩展(例如/image.jpg)
- URL 参数(例如?format=jpg)
- HTTP 接受标头(例如。接受:图像/jpg)
By default, Spring looks at the extensionrather than the Accept
header. This behaviour can be changed if you implement a @Configuration
class that extends WebMvcConfigurerAdapter
(or since Spring 5.0 simply implement WebMvcConfigurer
. There you can override configureContentNegotiation(ContentNegotiationConfigurer configurer)
and configure the ContentNegotiationConfigurer
to your needs, eg. by calling
默认情况下,Spring 查看扩展名而不是Accept
标题。如果您实现一个@Configuration
扩展的类WebMvcConfigurerAdapter
(或者从 Spring 5.0 开始简单地实现WebMvcConfigurer
. 在那里您可以覆盖configureContentNegotiation(ContentNegotiationConfigurer configurer)
和配置ContentNegotiationConfigurer
您的需要,例如通过调用
ContentNegotiationConfigurer#favorParameter
ContentNegotiationConfigurer#favorPathExtension
If you set both to false
, then Spring will look at the Accept
header. Since your client can say Accept: image/*,application/json
and handle both, Spring should be able to return either the image or the error JSON.
如果您将两者都设置为false
,则 Spring 将查看Accept
标题。由于您的客户端可以说Accept: image/*,application/json
和处理两者,因此 Spring 应该能够返回图像或错误 JSON。
See this Spring tutorialon content negotiation for more information and examples.
有关更多信息和示例,请参阅有关内容协商的Spring 教程。
回答by naXa
Pay attention to your HTTP Accept header. For example, if your controller produces "application/octet-stream" (in response), your Accept header should NOT be "application/json" (in request):
请注意您的 HTTP Accept 标头。例如,如果您的控制器生成“application/octet-stream”(作为响应),则您的 Accept 标头不应是“application/json”(在请求中):
@GetMapping(value = "/download", produces = MediaType.APPLICATION_OCTET_STREAM_VALUE)
public void download(HttpServletResponse response) {}