【问题标题】:Add a body to a 404 Not Found Exception将正文添加到 404 Not Found 异常
【发布时间】:2016-08-19 07:34:34
【问题描述】:

在使用 JHipster 生成的 REST API 中,我想抛出一些 404 异常。它通常是用

完成的
return new ResponseEntity<>(HttpStatus.NOT_FOUND);

这实际上会导致对 xhr 请求的 404 响应。问题是在前端,JHipster 用

解析响应
angular.fromJson(result)

当实际响应为 404 时,结果为空,导致解析失败。

如果我指向一个未映射的 URI,比如说 /api/user,而我的控制器映射到 /api/users(注意复数),我从 API 获得的 404 中有一个正文:

{
    "timestamp": "2016-04-25T18:33:19.947+0000",
    "status": 404,
    "error": "Not Found",
    "message": "No message available",
    "path": "/api/user/myuser/contact"
}

角度解析正确。

我怎样才能创造出这样的身体?这个异常是spring抛出的还是tomcat抛出的?

我试过这个:Trigger 404 in Spring-MVC controller? 但我无法设置响应的参数。

【问题讨论】:

    标签: java rest spring-mvc spring-boot jhipster


    【解决方案1】:

    抛出新的 ResponseStatusException(HttpStatus.NOT_FOUND, "message");

    【讨论】:

    • 您的答案可以通过额外的支持信息得到改进。请edit 添加更多详细信息,例如引用或文档,以便其他人可以确认您的答案是正确的。你可以找到更多关于如何写好答案的信息in the help center
    【解决方案2】:

    如果您想返回一些消息或使用错误代码进行测试,我想您可以这样做

    @ResponseBody
    public ResponseEntity somthing() {
    HttpHeaders headers = new HttpHeaders();
    headers.add("Content-Type", "application/json; charset=utf-8");
    return new ResponseEntity<>(new Gson().toJson("hello this is my message"), headers, HttpStatus.NOT_FOUND);
    }
    

    【讨论】:

      【解决方案3】:

      基本思路


      第一个选项是定义错误对象并将它们作为404 Not Found 正文返回。类似于以下内容:

      Map<String, String> errors = ....;
      return ResponseEntity.status(HttpStatus.NOT_FOUND).body(errors);
      

      您可以抛出一个Exception,而不是返回一个典型的ResponseEntity,它将被解析为404 Not Found。假设你有一个 NotFoundException 喜欢:

      @ResponseStatus(code = HttpStatus.NOT_FOUND)
      public class NotFoundException extends RuntimeException {}
      

      然后,如果您在控制器中抛出此异常,您会看到如下内容:

      {  
         "timestamp":1461621047967,
         "status":404,
         "error":"Not Found",
         "exception":"NotFoundException",
         "message":"No message available",
         "path":"/greet"
      }
      

      如果你想自定义消息和正文的其他部分,你应该为NotFoundException定义一个ExceptionHandler

      引入异常层次结构


      如果您正在创建 RESTful API 并希望针对不同的异常情况使用不同的错误代码错误消息,您可以创建表示这些情况的异常层次结构并从中提取消息和代码。

      例如,您可以引入一个异常,例如 APIException,它是您的控制器抛出的所有其他异常的超类。这个类定义了一个代码/消息对,如:

      public class APIException extends RuntimeException {
          private final int code;
          private final String message;
      
          APIException(int code, String message) {
              this.code = code;
              this.message = message;
          }
      
          public int code() {
              return code;
          }
      
          public String message() {
              return message;
          }
      }
      

      每个子类根据其异常的性质可以为这对提供一些合理的值。例如,我们可以有一个InvalidStateException

      @ResponseStatus(code = HttpStatus.BAD_REQUEST)
      public class InvalidStateException extends APIException {
          public InvalidStateException() {
              super(1, "Application is in invalid state");
          }
      }
      

      或者那些臭名昭著的找不到的:

      @ResponseStatus(code = HttpStatus.NOT_FOUND)
      public class SomethingNotFoundException extends APIException {
          public SomethingNotFoundException() {
              super(2, "Couldn't find something!");
          }
      }
      

      然后我们应该定义一个ErrorController 来捕获这些异常并将它们转换为有意义的 JSON 表示。该错误控制器可能如下所示:

      @RestController
      public class APIExceptionHandler extends AbstractErrorController {
          private static final String ERROR_PATH = "/error";
          private final ErrorAttributes errorAttributes;
      
          @Autowired
          public APIExceptionHandler(ErrorAttributes errorAttributes) {
              super(errorAttributes);
              this.errorAttributes = errorAttributes;
          }
      
          @RequestMapping(path = ERROR_PATH)
          public ResponseEntity<?> handleError(HttpServletRequest request) {
              HttpStatus status = getStatus(request);
      
              Map<String, Object> errors = getErrorAttributes(request, false);
              getApiException(request).ifPresent(apiError -> {
                  errors.put("message" , apiError.message());
                  errors.put("code", apiError.code());
              });
              // If you don't want to expose exception!
              errors.remove("exception");
      
      
              return ResponseEntity.status(status).body(errors);
          }
      
          @Override
          public String getErrorPath() {
              return ERROR_PATH;
          }
      
          private Optional<APIException> getApiException(HttpServletRequest request) {
              RequestAttributes attributes = new ServletRequestAttributes(request);
              Throwable throwable = errorAttributes.getError(attributes);
              if (throwable instanceof APIException) {
                  APIException exception = (APIException) throwable;
                  return Optional.of(exception);
              }
      
              return Optional.empty();
          }
      }
      

      所以,如果你抛出一个SomethingNotFoundException,返回的 JSON 会是这样的:

      {  
         "timestamp":1461621047967,
         "status":404,
         "error":"Not Found",
         "message":"Couldn't find something!",
         "code": 2,
         "path":"/greet"
      }
      

      【讨论】:

      • 谢谢阿里,但这样我无法定义消息。我尝试在 @ResponseStatus(value = HttpStatus.NOT_FOUND, reason="Resource not found") 中添加原因属性,但是响应类似于 {"message":"error.404","description":"Resource not找到","fieldErrors":null}
      • 顺便说一句,我以这种方式抛出它 return Optional.ofNullable(entity) .map(result -> new ResponseEntity(result, HttpStatus.OK)) .orElseThrow(HTTPNotFoundException::new);
      • 你知道我是否可以轻松记录使用@ResponseStatus 映射的所有异常吗?
      • 此代码不起作用:errorAttributes.getError 预期 WebRequest 不是 RequestAttributes
      猜你喜欢
      • 2012-12-22
      • 1970-01-01
      • 1970-01-01
      • 2020-06-29
      • 1970-01-01
      • 2021-02-17
      • 1970-01-01
      • 2015-06-27
      • 2018-08-22
      相关资源
      最近更新 更多