Spring Boot REST服务异常处理


172

我正在尝试建立一个大型的REST服务服务器。我们正在使用Spring Boot 1.2.1,Spring 4.1.5和Java8。我们的控制器正在实现@RestController和标准的@RequestMapping注释。

我的问题是Spring Boot为控制器异常设置了默认重定向到/error。从文档:

Spring Boot默认提供一个/ error映射,以一种明智的方式处理所有错误,并且在servlet容器中被注册为“全局”错误页面。

对使用Node.js编写REST应用程序已有多年的经验,对我而言,这绝非明智之举。服务端点生成的任何异常都应在响应中返回。我不明白为什么您要发送重定向到最有可能是Angular或JQuery SPA使用者的重定向程序,该使用者仅在寻找答案并且不能或不会对重定向采取任何措施。

我想做的是设置一个可以接受任何异常的全局错误处理程序-有目的地从请求映射方法抛出,或者由Spring自动生成(如果未为请求路径签名找到处理程序方法,则为404),然后返回标准格式的错误响应(400、500、503、404)到客户端,而无需任何MVC重定向。具体来说,我们将处理错误,使用UUID将其记录到NoSQL,然后将正确的HTTP错误代码与JSON主体中的日志条目的UUID返回给客户端。

文档对如何执行此操作一直含糊不清。在我看来,您必须创建自己的ErrorController实现或以某种方式使用ControllerAdvice,但是我所看到的所有示例仍然包括将响应转发到某种错误映射,这没有帮助。其他示例建议您必须列出要处理的每个Exception类型,而不是仅列出“ Throwable”并获取所有内容。

谁能告诉我我错过了什么,或者在没有暗示Node.js更容易处理的前提下为我指出正确的方向?


6
客户端实际上从未发送过重定向。重定向由servlet容器(例如Tomcat)在内部处理。
OrangeDog

1
我需要在异常处理程序上删除@ResponseStatus批注;参见stackoverflow.com/questions/35563968/…–
pmorken

Answers:


131

新答案(2016-04-20)

使用Spring Boot 1.3.1.RELEASE

新的第1步-将以下属性添加到application.properties很容易且不那么麻烦:

spring.mvc.throw-exception-if-no-handler-found=true
spring.resources.add-mappings=false

比修改现有的DispatcherServlet实例(如下所示)要容易得多!-JO'

如果使用完整的RESTful应用程序,则禁用静态资源的自动映射非常重要,因为如果您使用Spring Boot的默认配置来处理静态资源,则资源处理程序将处理请求(最后排序,并映射到/ **,这意味着它将拾取应用程序中其他任何处理程序未处理的任何请求),因此调度程序Servlet不会有机会引发异常。


新答案(2015-12-04)

使用Spring Boot 1.2.7.RELEASE

新的第1步-我发现设置“ throExceptionIfNoHandlerFound”标志的方式不太麻烦。在应用程序初始化类中,用下面的代码替换下面的DispatcherServlet替换代码(第1步):

@ComponentScan()
@EnableAutoConfiguration
public class MyApplication extends SpringBootServletInitializer {
    private static Logger LOG = LoggerFactory.getLogger(MyApplication.class);
    public static void main(String[] args) {
        ApplicationContext ctx = SpringApplication.run(MyApplication.class, args);
        DispatcherServlet dispatcherServlet = (DispatcherServlet)ctx.getBean("dispatcherServlet");
        dispatcherServlet.setThrowExceptionIfNoHandlerFound(true);
    }

在这种情况下,我们将在现有DispatcherServlet上设置标志,该标志将保留Spring Boot框架的所有自动配置。

我发现的另一件事-@EnableWebMvc注释对Spring Boot来说是致命的。是的,该注释使能够像下面所述捕获所有控制器异常之类的事情,但是它也杀死了Spring Boot通常提供的很多有用的自动配置。使用Spring Boot时请格外小心。


原始答案:

经过大量研究并跟踪了此处发布的解决方案(感谢帮助!),并在Spring代码中进行了大量的运行时跟踪,最终我找到了一个可处理所有异常(不是错误,但请继续阅读)的配置。包括404。

步骤1-告诉SpringBoot在“找不到处理程序”的情况下停止使用MVC。我们希望Spring抛出异常,而不是将返回到“ / error”的视图返回给客户端。为此,您需要在一个配置类中有一个条目:

// NEW CODE ABOVE REPLACES THIS! (2015-12-04)
@Configuration
public class MyAppConfig {
    @Bean  // Magic entry 
    public DispatcherServlet dispatcherServlet() {
        DispatcherServlet ds = new DispatcherServlet();
        ds.setThrowExceptionIfNoHandlerFound(true);
        return ds;
    }
}

这样做的缺点是它将替换默认的调度程序servlet。对于我们来说,这还不是问题,没有副作用或执行问题。如果出于其他原因要对调度程序servlet进行其他操作,则可以在这里进行操作。

第2步-现在,如果没有找到处理程序,spring boot将引发异常,那么可以在统一的异常处理程序中与其他任何异常一起处理:

@EnableWebMvc
@ControllerAdvice
public class ServiceExceptionHandler extends ResponseEntityExceptionHandler {

    @ExceptionHandler(Throwable.class)
    @ResponseBody
    ResponseEntity<Object> handleControllerException(HttpServletRequest req, Throwable ex) {
        ErrorResponse errorResponse = new ErrorResponse(ex);
        if(ex instanceof ServiceException) {
            errorResponse.setDetails(((ServiceException)ex).getDetails());
        }
        if(ex instanceof ServiceHttpException) {
            return new ResponseEntity<Object>(errorResponse,((ServiceHttpException)ex).getStatus());
        } else {
            return new ResponseEntity<Object>(errorResponse,HttpStatus.INTERNAL_SERVER_ERROR);
        }
    }

    @Override
    protected ResponseEntity<Object> handleNoHandlerFoundException(NoHandlerFoundException ex, HttpHeaders headers, HttpStatus status, WebRequest request) {
        Map<String,String> responseBody = new HashMap<>();
        responseBody.put("path",request.getContextPath());
        responseBody.put("message","The URL you have reached is not in service at this time (404).");
        return new ResponseEntity<Object>(responseBody,HttpStatus.NOT_FOUND);
    }
    ...
}

请记住,我认为“ @EnableWebMvc”注释在这里很重要。似乎没有它,所有这些都不起作用。就是这样-您的Spring Boot应用程序现在将在上述处理程序类中捕获所有异常,包括404,您可以根据需要使用它们。

最后一点-似乎没有一种方法来捕获引发的错误。我有一个古怪的想法,就是使用方面来捕获错误并将其转换为上述代码可以处理的异常,但是我还没有时间实际尝试实现这些错误。希望这对某人有帮助。

任何意见/更正/增强将不胜感激。


除了创建新的调度程序servlet bean之外,还可以在后处理器中翻转该标志:YourClass实现BeanPostProcessor {...在我们的异常处理程序插入((DispatcherServlet)bean).setThrowExceptionIfNoHandlerFound(true);之前得到404。} return bean; }公共对象postProcessAfterInitialization(Object bean,String beanName)抛出BeansException {return bean; }
wwadge

1
我有这个问题,但是自定义DispatcherServlet对我来说不起作用。Boot使用此额外的bean和配置是否需要其他任何魔术?
IanGilham 2015年

3
@IanGilham我也无法使用Spring Boot 1.2.7。尽管@ExceptionHandler将它们放入@ControllerAdvice类中也可以正常工作,但我什至没有得到任何 调用的方法@RestController@EnableWebMvc@ControllerAdvice@Configuration(我测试了每种组合)类上。有什么想法或可行的例子吗?// @Andy Wilkinson
FrVaBe 2015年

1
谁阅读了这个问题和答案,应该看看github上相应的SpringBoot问题。
FrVaBe 2015年

1
不确定@agpt。我有一个内部项目,可以升级到1.3.0,然后查看对设置产生的影响,并告诉您我所发现的内容。
ogradyjd 2015年

41

在Spring Boot 1.4+中,添加了新的酷类以简化异常处理,这有助于删除样板代码。

@RestControllerAdvice提供了一个新的异常处理,它是@ControllerAdvice和的组合@ResponseBody。使用此新注释时,可以删除@ResponseBodyon @ExceptionHandler方法。

@RestControllerAdvice
public class GlobalControllerExceptionHandler {

    @ExceptionHandler(value = { Exception.class })
    @ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
    public ApiErrorResponse unknownException(Exception ex, WebRequest req) {
        return new ApiErrorResponse(...);
    }
}

为了处理404错误@EnableWebMvc,在application.properties中添加注释和以下内容就足够了:
spring.mvc.throw-exception-if-no-handler-found=true

您可以在这里找到并使用这些资源:https :
//github.com/magiccrafter/spring-boot-exception-handling


7
真的很有帮助,谢谢。但是我不明白为什么我们需要用spring.mvc.throw-exception-if-no-handler-found = true`来@EnableWebMvc`。我的期望是@RestControllerAdvice无需额外配置即可处理所有异常。我在这里想念什么?
fiskra

28

我认为ResponseEntityExceptionHandler符合您的要求。HTTP 400的示例代码片段:

@ControllerAdvice
public class MyExceptionHandler extends ResponseEntityExceptionHandler {

  @ResponseStatus(value = HttpStatus.BAD_REQUEST)
  @ExceptionHandler({HttpMessageNotReadableException.class, MethodArgumentNotValidException.class,
      HttpRequestMethodNotSupportedException.class})
  public ResponseEntity<Object> badRequest(HttpServletRequest req, Exception exception) {
    // ...
  }
}

您可以查看此帖子


6
我在执行此代码之前和之后都已经看过这段代码,该类确实捕获了控制器requestmapping方法中引发的异常。这仍然无法捕获404错误,该错误已在ResourceHttpRequestHandler.handleRequest方法中处理,或者,如果使用@EnableWebMvc批注,则在DispatcherServlet.noHandlerFound中得到处理。我们想处理任何错误,包括404错误,但是最新版本的Spring Boot似乎很难做到这一点。
ogradyjd 2015年

我写了相同的方法来处理HttpRequestMethodNotSupportedException和插入多个微服务中的同一jar,出于某种业务目的,我们需要在响应中响应微服务别名。有什么方法可以获取底层微服务名称/控制器名称?我知道HandlerMethod将从异常起源的地方提供java方法名称。但是在这里,没有方法收到请求,因此HandlerMethod不会被初始化。那么有什么解决方案可以解决这个问题吗?
Paramesh Korrakuti

控制器建议是一种很好的方法,但是请始终记住,异常不是异常情况下必须发生的流程的一部分!
JorgeTovar

17

尽管这是一个比较老的问题,但我想分享一下我的想法。希望对您中的某些人有所帮助。

我当前正在构建一个REST API,该API使用Spring Boot 1.5.2.RELEASE和Spring Framework 4.3.7.RELEASE。我使用Java Config方法(与XML配置相反)。另外,我的项目使用带有@RestControllerAdvice注释的全局异常处理机制(请参阅下文)。

我的项目与您的项目具有相同的要求:我希望我的REST API HTTP 404 Not Found在尝试向不存在的URL发送请求时,在HTTP响应中返回一个带有JSON有效载荷的HTTP响应给API客户端。就我而言,JSON有效负载看起来像这样(显然与Spring Boot的默认值btw不同):

{
    "code": 1000,
    "message": "No handler found for your request.",
    "timestamp": "2017-11-20T02:40:57.628Z"
}

我终于做到了。这是您需要简要完成的主要任务:

  • NoHandlerFoundException如果API客户端调用不存在任何处理程序方法的URL,请确保将抛出异常(请参见下面的步骤1)。
  • 创建一个自定义错误类(以我为例ApiError),其中包含应返回给API客户端的所有数据(请参见步骤2)。
  • 创建一个异常处理程序,该异常处理程序对做出反应NoHandlerFoundException ,并向API客户端返回正确的错误消息(请参见步骤3)。
  • 为此编写一个测试,并确保它可以正常工作(请参阅步骤4)。

好的,现在转到细节:

步骤1:配置application.properties

我必须将以下两个配置设置添加到项目的application.properties文件中:

spring.mvc.throw-exception-if-no-handler-found=true
spring.resources.add-mappings=false

这可以确保NoHandlerFoundException在客户端尝试访问没有控制器方法可以处理请求的URL时抛出。

步骤2:为API错误创建类

我在Eugen Paraschiv的博客上做了类似于本文中建议的课程。此类表示API错误。发生错误时,此信息将通过HTTP响应主体发送到客户端。

public class ApiError {

    private int code;
    private String message;
    private Instant timestamp;

    public ApiError(int code, String message) {
        this.code = code;
        this.message = message;
        this.timestamp = Instant.now();
    }

    public ApiError(int code, String message, Instant timestamp) {
        this.code = code;
        this.message = message;
        this.timestamp = timestamp;
    }

    // Getters and setters here...
}

步骤3:创建/配置全局异常处理程序

我使用以下类来处理异常(为简单起见,我删除了import语句,日志记录代码和其他一些不相关的代码段):

@RestControllerAdvice
public class GlobalExceptionHandler {

    @ExceptionHandler(NoHandlerFoundException.class)
    @ResponseStatus(HttpStatus.NOT_FOUND)
    public ApiError noHandlerFoundException(
            NoHandlerFoundException ex) {

        int code = 1000;
        String message = "No handler found for your request.";
        return new ApiError(code, message);
    }

    // More exception handlers here ...
}

步骤4:编写测试

我想确保,即使在失败的情况下,API也会始终将正确的错误消息返回给调用客户端。因此,我编写了这样的测试:

@RunWith(SpringRunner.class)
@SpringBootTest(webEnvironment = SprintBootTest.WebEnvironment.RANDOM_PORT)
@AutoConfigureMockMvc
@ActiveProfiles("dev")
public class GlobalExceptionHandlerIntegrationTest {

    public static final String ISO8601_DATE_REGEX =
        "^\\d{4}-\\d{2}-\\d{2}T\\d{2}:\\d{2}:\\d{2}\\.\\d{3}Z$";

    @Autowired
    private MockMvc mockMvc;

    @Test
    @WithMockUser(roles = "DEVICE_SCAN_HOSTS")
    public void invalidUrl_returnsHttp404() throws Exception {
        RequestBuilder requestBuilder = getGetRequestBuilder("/does-not-exist");
        mockMvc.perform(requestBuilder)
            .andExpect(status().isNotFound())
            .andExpect(jsonPath("$.code", is(1000)))
            .andExpect(jsonPath("$.message", is("No handler found for your request.")))
            .andExpect(jsonPath("$.timestamp", RegexMatcher.matchesRegex(ISO8601_DATE_REGEX)));
    }

    private RequestBuilder getGetRequestBuilder(String url) {
        return MockMvcRequestBuilders
            .get(url)
            .accept(MediaType.APPLICATION_JSON);
    }

@ActiveProfiles("dev")注解可以留下了。我仅在使用不同的配置文件时使用它。这RegexMatcher是我用来更好地处理时间戳字段的自定义Hamcrest匹配器。这是代码(我在这里找到):

public class RegexMatcher extends TypeSafeMatcher<String> {

    private final String regex;

    public RegexMatcher(final String regex) {
        this.regex = regex;
    }

    @Override
    public void describeTo(final Description description) {
        description.appendText("matches regular expression=`" + regex + "`");
    }

    @Override
    public boolean matchesSafely(final String string) {
        return string.matches(regex);
    }

    // Matcher method you can call on this matcher class
    public static RegexMatcher matchesRegex(final String string) {
        return new RegexMatcher(regex);
    }
}

我这边还有一些注意事项:

  • 在StackOverflow上的许多其他帖子中,人们建议设置@EnableWebMvc注释。就我而言,这不是必需的。
  • 这种方法与MockMvc配合使用效果很好(请参见上面的测试)。

这为我解决了问题。只是要添加,我缺少了@ RestControllerAdvice批注,所以我将其与@ControllerAdvice批注一起添加,以便它可以处理所有内容,并且达到了目的。
PGMacDesign '18年

13

这段代码呢?我使用后备请求映射来捕获404错误。

@Controller
@ControllerAdvice
public class ExceptionHandlerController {

    @ExceptionHandler(Exception.class)
    public ModelAndView exceptionHandler(HttpServletRequest request, HttpServletResponse response, Exception ex) {
        //If exception has a ResponseStatus annotation then use its response code
        ResponseStatus responseStatusAnnotation = AnnotationUtils.findAnnotation(ex.getClass(), ResponseStatus.class);

        return buildModelAndViewErrorPage(request, response, ex, responseStatusAnnotation != null ? responseStatusAnnotation.value() : HttpStatus.INTERNAL_SERVER_ERROR);
    }

    @RequestMapping("*")
    public ModelAndView fallbackHandler(HttpServletRequest request, HttpServletResponse response) throws Exception {
        return buildModelAndViewErrorPage(request, response, null, HttpStatus.NOT_FOUND);
    }

    private ModelAndView buildModelAndViewErrorPage(HttpServletRequest request, HttpServletResponse response, Exception ex, HttpStatus httpStatus) {
        response.setStatus(httpStatus.value());

        ModelAndView mav = new ModelAndView("error.html");
        if (ex != null) {
            mav.addObject("title", ex);
        }
        mav.addObject("content", request.getRequestURL());
        return mav;
    }

}

6

默认情况下,Spring Boot为json提供错误详细信息。

curl -v localhost:8080/greet | json_pp
[...]
< HTTP/1.1 400 Bad Request
[...]
{
   "timestamp" : 1413313361387,
   "exception" : "org.springframework.web.bind.MissingServletRequestParameterException",
   "status" : 400,
   "error" : "Bad Request",
   "path" : "/greet",
   "message" : "Required String parameter 'name' is not present"
}

它还适用于所有类型的请求映射错误。检查这篇文章 http://www.jayway.com/2014/10/19/spring-boot-error-responses/

如果要创建,请将其记录到NoSQL。您可以在要记录它的位置创建@ControllerAdvice,然后重新引发异常。文档https://spring.io/blog/2013/11/01/exception-handling-in-spring-mvc中有一个示例


默认的DispatcherServlet被硬编码为使用MVC进行重定向,而不是在收到不存在的映射请求时引发异常-除非像我在上一篇文章中那样设置标志。
ogradyjd 2015年

同样,我们实现ResponseEntityExceptionHandler类的原因是,我们可以控制输出的格式并将错误堆栈跟踪记录到NoSQL解决方案,然后发送客户端安全的错误消息。
ogradyjd 2015年

6

@RestControllerAdvice是Spring Framework 4.3的新功能,可通过跨领域关注解决方案处理RestfulApi的异常:

 package com.khan.vaquar.exception;

import javax.servlet.http.HttpServletRequest;

import org.owasp.esapi.errors.IntrusionException;
import org.owasp.esapi.errors.ValidationException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.http.HttpStatus;
import org.springframework.web.bind.MissingServletRequestParameterException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseStatus;
import org.springframework.web.bind.annotation.RestControllerAdvice;
import org.springframework.web.servlet.NoHandlerFoundException;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.khan.vaquar.domain.ErrorResponse;

/**
 * Handles exceptions raised through requests to spring controllers.
 **/
@RestControllerAdvice
public class RestExceptionHandler {

    private static final String TOKEN_ID = "tokenId";

    private static final Logger log = LoggerFactory.getLogger(RestExceptionHandler.class);

    /**
     * Handles InstructionExceptions from the rest controller.
     * 
     * @param e IntrusionException
     * @return error response POJO
     */
    @ResponseStatus(HttpStatus.BAD_REQUEST)
    @ExceptionHandler(value = IntrusionException.class)
    public ErrorResponse handleIntrusionException(HttpServletRequest request, IntrusionException e) {       
        log.warn(e.getLogMessage(), e);
        return this.handleValidationException(request, new ValidationException(e.getUserMessage(), e.getLogMessage()));
    }

    /**
     * Handles ValidationExceptions from the rest controller.
     * 
     * @param e ValidationException
     * @return error response POJO
     */
    @ResponseStatus(HttpStatus.BAD_REQUEST)
    @ExceptionHandler(value = ValidationException.class)
    public ErrorResponse handleValidationException(HttpServletRequest request, ValidationException e) {     
        String tokenId = request.getParameter(TOKEN_ID);
        log.info(e.getMessage(), e);

        if (e.getUserMessage().contains("Token ID")) {
            tokenId = "<OMITTED>";
        }

        return new ErrorResponse(   tokenId,
                                    HttpStatus.BAD_REQUEST.value(), 
                                    e.getClass().getSimpleName(),
                                    e.getUserMessage());
    }

    /**
     * Handles JsonProcessingExceptions from the rest controller.
     * 
     * @param e JsonProcessingException
     * @return error response POJO
     */
    @ResponseStatus(HttpStatus.BAD_REQUEST)
    @ExceptionHandler(value = JsonProcessingException.class)
    public ErrorResponse handleJsonProcessingException(HttpServletRequest request, JsonProcessingException e) {     
        String tokenId = request.getParameter(TOKEN_ID);
        log.info(e.getMessage(), e);
        return new ErrorResponse(   tokenId,
                                    HttpStatus.BAD_REQUEST.value(), 
                                    e.getClass().getSimpleName(),
                                    e.getOriginalMessage());
    }

    /**
     * Handles IllegalArgumentExceptions from the rest controller.
     * 
     * @param e IllegalArgumentException
     * @return error response POJO
     */
    @ResponseStatus(HttpStatus.BAD_REQUEST)
    @ExceptionHandler(value = IllegalArgumentException.class)
    public ErrorResponse handleIllegalArgumentException(HttpServletRequest request, IllegalArgumentException e) {
        String tokenId = request.getParameter(TOKEN_ID);
        log.info(e.getMessage(), e);
        return new ErrorResponse(   tokenId,
                                    HttpStatus.BAD_REQUEST.value(), 
                                    e.getClass().getSimpleName(), 
                                    e.getMessage());
    }

    @ResponseStatus(HttpStatus.BAD_REQUEST)
    @ExceptionHandler(value = UnsupportedOperationException.class)
    public ErrorResponse handleUnsupportedOperationException(HttpServletRequest request, UnsupportedOperationException e) {
        String tokenId = request.getParameter(TOKEN_ID);
        log.info(e.getMessage(), e);
        return new ErrorResponse(   tokenId,
                                    HttpStatus.BAD_REQUEST.value(), 
                                    e.getClass().getSimpleName(), 
                                    e.getMessage());
    }

    /**
     * Handles MissingServletRequestParameterExceptions from the rest controller.
     * 
     * @param e MissingServletRequestParameterException
     * @return error response POJO
     */
    @ResponseStatus(HttpStatus.BAD_REQUEST)
    @ExceptionHandler(value = MissingServletRequestParameterException.class)
    public ErrorResponse handleMissingServletRequestParameterException( HttpServletRequest request, 
                                                                        MissingServletRequestParameterException e) {
        String tokenId = request.getParameter(TOKEN_ID);
        log.info(e.getMessage(), e);
        return new ErrorResponse(   tokenId,
                                    HttpStatus.BAD_REQUEST.value(), 
                                    e.getClass().getSimpleName(), 
                                    e.getMessage());
    }

    /**
     * Handles NoHandlerFoundExceptions from the rest controller.
     * 
     * @param e NoHandlerFoundException
     * @return error response POJO
     */
    @ResponseStatus(HttpStatus.NOT_FOUND)
    @ExceptionHandler(value = NoHandlerFoundException.class)
    public ErrorResponse handleNoHandlerFoundException(HttpServletRequest request, NoHandlerFoundException e) {
        String tokenId = request.getParameter(TOKEN_ID);
        log.info(e.getMessage(), e);
        return new ErrorResponse(   tokenId,
                                    HttpStatus.NOT_FOUND.value(), 
                                    e.getClass().getSimpleName(), 
                                    "The resource " + e.getRequestURL() + " is unavailable");
    }

    /**
     * Handles all remaining exceptions from the rest controller.
     * 
     * This acts as a catch-all for any exceptions not handled by previous exception handlers.
     * 
     * @param e Exception
     * @return error response POJO
     */
    @ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
    @ExceptionHandler(value = Exception.class)
    public ErrorResponse handleException(HttpServletRequest request, Exception e) {
        String tokenId = request.getParameter(TOKEN_ID);
        log.error(e.getMessage(), e);
        return new ErrorResponse(   tokenId,
                                    HttpStatus.INTERNAL_SERVER_ERROR.value(), 
                                    e.getClass().getSimpleName(), 
                                    "An internal error occurred");
    }   

}

3

对于REST控制器,我建议使用Zalando Problem Spring Web

https://github.com/zalando/problem-spring-web

如果Spring Boot的目标是嵌入一些自动配置,那么该库可以做更多的异常处理。您只需要添加依赖项:

<dependency>
    <groupId>org.zalando</groupId>
    <artifactId>problem-spring-web</artifactId>
    <version>LATEST</version>
</dependency>

然后为您的异常定义一个或多个建议特征(或使用默认提供的特征)

public interface NotAcceptableAdviceTrait extends AdviceTrait {

    @ExceptionHandler
    default ResponseEntity<Problem> handleMediaTypeNotAcceptable(
            final HttpMediaTypeNotAcceptableException exception,
            final NativeWebRequest request) {
        return Responses.create(Status.NOT_ACCEPTABLE, exception, request);
    }

}

然后,可以将异常处理的控制器建议定义为:

@ControllerAdvice
class ExceptionHandling implements MethodNotAllowedAdviceTrait, NotAcceptableAdviceTrait {

}

2

对于希望根据http状态码进行响应的人,可以使用以下ErrorController方式:

@Controller
public class CustomErrorController extends BasicErrorController {

    public CustomErrorController(ServerProperties serverProperties) {
        super(new DefaultErrorAttributes(), serverProperties.getError());
    }

    @Override
    public ResponseEntity error(HttpServletRequest request) {
        HttpStatus status = getStatus(request);
        if (status.equals(HttpStatus.INTERNAL_SERVER_ERROR)){
            return ResponseEntity.status(status).body(ResponseBean.SERVER_ERROR);
        }else if (status.equals(HttpStatus.BAD_REQUEST)){
            return ResponseEntity.status(status).body(ResponseBean.BAD_REQUEST);
        }
        return super.error(request);
    }
}

ResponseBean是我自定义的pojo,用于回应。


0

Spring Boot 1.3.1的解决方案 dispatcherServlet.setThrowExceptionIfNoHandlerFound(true);@EnableWebMvc @ControllerAdvice为我工作,而不适用于1.2.7

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.