java Spring @ExceptionHandler 和 HttpMediaTypeNotAcceptableException

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/32123540/
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

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-11-02 19:41:32  来源:igfitidea点击:

Spring @ExceptionHandler and HttpMediaTypeNotAcceptableException

javaspringexceptionexception-handling

提问by Lia

I have a class annotated with @ControllerAdviceand this method in it:

我有一个带有注释的类,其中包含@ControllerAdvice此方法:

@ExceptionHandler(ResourceNotFoundException.class)
@ResponseStatus(HttpStatus.NOT_FOUND)
@ResponseBody
public ExceptionInfo resourceNotFoundHandler(ResourceNotFoundException ex) {
    List<ErrorContent> errors = new ArrayList<>();
    errors.add(new ErrorContent(ExceptionsCodes.NOT_FOUND_CODE, null,
            "test"));
    return fillExceptionInfo(HttpStatus.NOT_FOUND, errors, ex);
}

Here is fillExceptionInfo:

这是fillExceptionInfo

public ExceptionInfo fillExceptionInfo(HttpStatus status, List<ErrorContent> errors, 
        Exception ex) {
    String msg = ex.getMessage();

    return new ExceptionInfo(status.toString(), errors, (msg != null && !msg.equals(""))
            ? ex.getMessage()
            : ExceptionUtils.getFullStackTrace(ex));
}

When a web-client send a request for some json data, which cannot be found, this method works ok. But when server receives a request to image, instead of my exception a HttpMediaTypeNotAcceptableExceptionis thrown. I understand that it happens because of wrong content type, but how can I fix this problem?

当 web 客户端发送一些 json 数据的请求,但找不到时,此方法可以正常工作。但是当服务器收到图像请求时,HttpMediaTypeNotAcceptableException抛出的不是我的异常。我知道这是由于错误的内容类型而发生的,但是我该如何解决这个问题?

Update

更新

My goal is to throw ResourceNotFoundExceptionin both cases for json data and for file.

我的目标是ResourceNotFoundException为 json 数据和文件抛出这两种情况。

Exception that I get (so it is thrown from AbstractMessageConverterMethodProcessor):

我得到的异常(所以它是从 抛出的AbstractMessageConverterMethodProcessor):

ERROR o.s.w.s.m.m.a.ExceptionHandlerExceptionResolver - doResolveHandlerMethodException - Failed to invoke @ExceptionHandler method: public com.lia.utils.GlobalExceptionHandler$ExceptionInfo com.lia.utils.GlobalExceptionHandler.resourceNotFoundHandler(com.lia.app.controllers.exceptions.ResourceNotFoundException) 
    org.springframework.web.HttpMediaTypeNotAcceptableException: Could not find acceptable representation
        at org.springframework.web.servlet.mvc.method.annotation.AbstractMessageConverterMethodProcessor.writeWithMessageConverters(AbstractMessageConverterMethodProcessor.java:168) ~[spring-webmvc-4.1.1.RELEASE.jar:4.1.1.RELEASE]
        at org.springframework.web.servlet.mvc.method.annotation.AbstractMessageConverterMethodProcessor.writeWithMessageConverters(AbstractMessageConverterMethodProcessor.java:101) ~[spring-webmvc-4.1.1.RELEASE.jar:4.1.1.RELEASE]
        at org.springframework.web.servlet.mvc.method.annotation.RequestResponseBodyMethodProcessor.handleReturnValue(RequestResponseBodyMethodProcessor.java:198) ~[spring-webmvc-4.1.1.RELEASE.jar:4.1.1.RELEASE]
        at org.springframework.web.method.support.HandlerMethodReturnValueHandlerComposite.handleReturnValue(HandlerMethodReturnValueHandlerComposite.java:71) ~[spring-web-4.1.1.RELEASE.jar:4.1.1.RELEASE]
        at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:122) ~[spring-webmvc-4.1.1.RELEASE.jar:4.1.1.RELEASE]
        at org.springframework.web.servlet.mvc.method.annotation.ExceptionHandlerExceptionResolver.doResolveHandlerMethodException(ExceptionHandlerExceptionResolver.java:362) ~[spring-webmvc-4.1.1.RELEASE.jar:4.1.1.RELEASE]
        at org.springframework.web.servlet.handler.AbstractHandlerMethodExceptionResolver.doResolveException(AbstractHandlerMethodExceptionResolver.java:60) [spring-webmvc-4.1.1.RELEASE.jar:4.1.1.RELEASE]
        at org.springframework.web.servlet.handler.AbstractHandlerExceptionResolver.resolveException(AbstractHandlerExceptionResolver.java:138) [spring-webmvc-4.1.1.RELEASE.jar:4.1.1.RELEASE]
        at org.springframework.web.servlet.DispatcherServlet.processHandlerException(DispatcherServlet.java:1167) [spring-webmvc-4.1.1.RELEASE.jar:4.1.1.RELEASE]
        at org.springframework.web.servlet.DispatcherServlet.processDispatchResult(DispatcherServlet.java:1004) [spring-webmvc-4.1.1.RELEASE.jar:4.1.1.RELEASE]
        at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:955) [spring-webmvc-4.1.1.RELEASE.jar:4.1.1.RELEASE]
        at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:877) [spring-webmvc-4.1.1.RELEASE.jar:4.1.1.RELEASE]
        at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:966) [spring-webmvc-4.1.1.RELEASE.jar:4.1.1.RELEASE]
        at org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:857) [spring-webmvc-4.1.1.RELEASE.jar:4.1.1.RELEASE]
        at javax.servlet.http.HttpServlet.service(HttpServlet.java:687) [javax.servlet-api-3.1.0.jar:3.1.0]
        at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:842) [spring-webmvc-4.1.1.RELEASE.jar:4.1.1.RELEASE]
        at javax.servlet.http.HttpServlet.service(HttpServlet.java:790) [javax.servlet-api-3.1.0.jar:3.1.0]
        at org.eclipse.jetty.servlet.ServletHolder.handle(ServletHolder.java:717) [jetty-servlet-9.1.1.v20140108.jar:9.1.1.v20140108]
        at org.eclipse.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1644) [jetty-servlet-9.1.1.v20140108.jar:9.1.1.v20140108]
....

采纳答案by Adam Michalik

The problem lies in the incompatibility of the requested content type and the object being returned. See my responseon how to configure the ContentNegotiationConfigurerso that Spring determines the requested content type according to your needs (looking at the path extension, URL parameter or Acceptheader).

问题在于请求的内容类型与返回的对象不兼容。请参阅关于如何配置ContentNegotiationConfigurer以便 Spring 根据您的需要确定请求的内容类型的回复(查看路径扩展名、URL 参数或Accept标头)。

Depending on how the requested content type is determined, you have following options when an image is requested by the client:

根据请求的内容类型的确定方式,当客户端请求图像时,您有以下选项:

  • if the requested content type is determined by the Acceptheader, and if the client can/wants to handle a JSON response instead of the image data, then the client should send the request with Accept: image/*, application/json. That way Spring knows that it can safely return either the image byte data or the error JSON message.
  • in any other case your best solution is to just return a HTTP error code, without any error message. You can do that in a couple of ways in your controller:
  • 如果请求的内容类型由Accept标头确定,并且客户端可以/想要处理 JSON 响应而不是图像数据,则客户端应发送带有Accept: image/*, application/json. 这样 Spring 就知道它可以安全地返回图像字节数据或错误 JSON 消息。
  • 在任何其他情况下,您最好的解决方案是只返回 HTTP 错误代码,而没有任何错误消息。您可以在控制器中通过几种方式做到这一点:

Set the error code on the response directly

直接在响应上设置错误代码

public byte[] getImage(HttpServletResponse resp) {
    try {
        // return your image
    } catch (Exception e) {
        resp.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
    }
}

Use ResponseEntity

利用 ResponseEntity

public ResponseEntity<?> getImage(HttpServletResponse resp) {
    try {
        byte[] img = // your image
        return ReponseEntity.ok(img);
    } catch (Exception e) {
        return new ResponseEntity(HttpStatus.INTERNAL_SERVER_ERROR);
    }
}

Use a separate @ExceptionHandlermethod in that controller, which will override the default Spring exception handling. That assumes you have either a dedicated exception type for image requests or a separate controller just for serving the images. Otherwise, the exception handler will handle exceptions from other endpoints in that controller, too.

在该控制器中使用一个单独的@ExceptionHandler方法,它将覆盖默认的 Spring 异常处理。这假设您有一个专门的图像请求异常类型或一个单独的控制器来提供图像。否则,异常处理程序也将处理来自该控制器中其他端点的异常。

回答by Szymon Stepniak

What does your ExceptionInfoclass look like? I run into quite similar issue after defining a few exception handlers in @ControllerAdviceannotated class. When exception happened it was caught, although the response was not return and org.springframework.web.HttpMediaTypeNotAcceptableException: Could not find acceptable representationwas thrown.

你的ExceptionInfo班级是什么样的?在带@ControllerAdvice注释的类中定义了一些异常处理程序后,我遇到了非常相似的问题。当异常发生时,它被捕获,尽管响应没有返回org.springframework.web.HttpMediaTypeNotAcceptableException: Could not find acceptable representation并被抛出。

I figured out that the problem was caused by the fact, that I missed to add getter methods to my ErrorResponseclass. After adding getter methods (this class was immutable, so there were no setter methods) everything worked like a charm.

我发现问题是由于我错过了向我的ErrorResponse类添加 getter 方法的事实造成的。添加 getter 方法(这个类是不可变的,所以没有 setter 方法)之后,一切都像魅力一样。