为了账号安全,请及时绑定邮箱和手机立即绑定

Spring Boot REST服务异常处理

/ 猿问

Spring Boot REST服务异常处理

烧仙草VB 2019-10-15 09:28:11

我正在尝试建立一个大型的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更容易处理的前提下为我指出正确的方向?


查看完整描述

3 回答

?
慕虎7371278

使用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步-现在,春天开机时会抛出异常时没有处理程序被发现,该异常可以在一个统一的异常处理任何其他处理:


@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启动应用程序现在将在上述处理程序类中捕获所有异常,包括404,您可以根据需要使用它们。


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


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


查看完整回答
反对 回复 2019-10-15
?
幕布斯6054654

在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


查看完整回答
反对 回复 2019-10-15
?
沧海一幻觉

我认为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) {

    // ...

  }

}


查看完整回答
反对 回复 2019-10-15

添加回答

回复

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信