抛出异常时,Spring Boot 不显示自定义错误

Posted

技术标签:

【中文标题】抛出异常时,Spring Boot 不显示自定义错误【英文标题】:Spring boot does not show custom error when exception is thrown 【发布时间】:2020-03-15 18:30:00 【问题描述】:

我对 Java/Spring 领域相当陌生,我正在尝试在我的 Spring Boot 应用程序中使用 @ControllerAdvice。 ControllerAdvice 捕获异常但不显示我的自定义响应。

以下是引发异常的RestController的快照

ResponseEntity<MyClass> response = new ResponseEntity<MyClass>(HttpStatus.OK);

    try    
        response = restTemplate.exchange(url, HttpMethod.GET, entity, MyClass.class);
     catch (HttpClientErrorException  ex)         
        throw ex;
    catch (HttpServerErrorException   ex) 
        logger.debug(ex.getMessage() + " Server Status Code - " + ex.getStatusCode());
    
    catch(Exception ex) 
        logger.debug(ex.getMessage() + " Generic Exception ");
    

以下是 @ControllerAdvice

@ControllerAdvice
public class GlobalExceptionHandler extends Exception 

    @ExceptionHandler(HttpClientErrorException.class)
    @ResponseStatus(HttpStatus.BAD_REQUEST)
    public ErrorResponse errorHandle(HttpClientErrorException ex) 

          String responseBody = ex.getResponseBodyAsString(); 

          ObjectMapper mapper = new ObjectMapper();
          mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
          ErrorResponse errorResponse = new ErrorResponse();
          try  
              errorResponse = mapper.readValue(responseBody, ErrorResponse.class); 

           catch (JsonMappingException e)  
          e.printStackTrace(); 
           catch (JsonProcessingException e)  
              e.printStackTrace(); 
          
        return errorResponse;
    

其他类

@JsonIgnoreProperties
public class ErrorResponse 
    @JsonProperty("error")
    public Error error;

      @JsonProperty("version") 
      public String version;



public class Error 
    @JsonProperty("code")
    public String Code;

    @JsonProperty("message")
    public String Message;

    public String getCode() 
        return Code;
    

    public void setCode(String code) 
        Code = code;
    

    public String getMessage() 
        return Message;
    

    public void setMessage(String message) 
        Message = message;
    


我在使用 POSTMAN 时遇到的错误是


    "timestamp": "2019-11-20T05:42:24.126+0000",
    "status": 404,
    "error": "Not Found",
    "message": "400 Bad Request",
    "path": "myApi/somecontroller"

我在浏览器上遇到的错误如下

Whitelabel Error Page
This application has no explicit mapping for /error, so you are seeing this as a fallback.

Tue Nov 19 23:40:26 CST 2019
There was an unexpected error (type=Not Found, status=404).
400 Bad Request

任何想法/建议为什么会出现这种行为?我期待 ErrorResponse 类的 JSON 表示。

更新

【问题讨论】:

This application has no explicit mapping for /error的可能重复 你在哪里定义了@Controller?看看这个***.com/questions/56648041/…这可能对你有帮助。 【参考方案1】:

这不是异常,这是错误场景

尝试使用以下代码。

@RestController
public class IndexController implements ErrorController

    private static final String PATH = "/error";

    @RequestMapping(value = PATH)
    public String error() 
        return "Error handling";
    

    @Override
    public String getErrorPath() 
        return PATH;
    

需要重写的Spring Boot默认寄存器BasicErrorController

【讨论】:

【参考方案2】:

在您的情况下,您有一个控制器建议方法,该方法返回特定异常的 Json 响应。因此,检查浏览器 ui 中的响应是没有意义的,因为您需要通过另一个异常处理程序配置适当的错误页面才能按您的意愿工作。否则会显示默认的spring白标错误页面。

对于其余的异常处理程序,我认为当您使用对象映射器创建实例时,JSON 结构没有得到正确转换。试试吧:

@ControllerAdvice
public class GlobalExceptionHandler extends Exception 

    @ExceptionHandler(HttpClientErrorException.class)
    @ResponseStatus(HttpStatus.BAD_REQUEST)
    public ErrorResponse errorHandle(HttpClientErrorException ex) 

          String responseBody = ex.getResponseBodyAsString(); // The response body structure is different, you should get the message and stacktrace separately and assign it to your own response object
          ErrorResponse errorResponse = new ErrorResponse();
          Error error = new Error();
          error.setMessage(ex.getMessage());
          error.setCode(HttpStatus.BAD_REQUEST);
          errorResponse.setError(error);
          return errorResponse;
    

getResponseBodyAsString - 返回转换为的响应正文 细绳。使用的字符集是响应“Content-Type”或 否则为“UTF-8”。

【讨论】:

最初我也想过这样做,但 ex.getMessage() 中的消息只是 String "400 BAD REQUEST" 但 String responseBody = ex.getResponseBodyAsString() 给出了正确的错误对象 @Karan 您能否尝试调试该方法并确保对象映射器以正确的方式填充 errorResponse 对象。 是的,我再次在调试模式下检查了这个。起初我还认为 ex.getMessage() 会给我整个对象,但事实并非如此。 添加了截图,请看一下 @Karan 您是否有适当的 getter 和 setter 用于 ErrorResponse 和 Error 对象来映射所有字段?【参考方案3】:

在进行了一些测试/搜索后,发现了这一点。使用下面的Controller就能做到这一点

@ControllerAdvice
public class GlobalExceptionHandler extends Exception 

    @ExceptionHandler(value =  HttpClientErrorException.class )
    public ResponseEntity<Object> handleResourceNotFoundException(HttpClientErrorException ex) 
        String responseBody = ex.getResponseBodyAsString();
        HttpHeaders headers = new HttpHeaders();

        headers.setContentType(MediaType.APPLICATION_JSON);     
        ObjectMapper mapper = new ObjectMapper();
        mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
        ErrorResponse errorResponse = new ErrorResponse(); 
        try  
            errorResponse = mapper.readValue(responseBody, ErrorResponse.class);         
         catch (JsonMappingException e)  
            e.printStackTrace(); 
             
        catch (JsonProcessingException e)  
                e.printStackTrace(); 
            

        ResponseEntity<Object> response = new ResponseEntity<>(errorResponse, headers, HttpStatus.BAD_REQUEST);

        return response;
    

【讨论】:

以上是关于抛出异常时,Spring Boot 不显示自定义错误的主要内容,如果未能解决你的问题,请参考以下文章

处理自定义转换器抛出的 Spring Boot REST 异常

在 Spring Boot 应用程序中防止自定义异常的堆栈跟踪日志记录

处理从自定义转换器抛出的Spring Boot REST中的异常

如何处理spring boot 2中@Requestbody中的对象抛出的异常

未抛出 spring webflux 的自定义异常

Spring Boot web自己的整理