将正文添加到 404 Not Found 异常

新手上路,请多包涵

在使用 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? 但我无法设置响应的参数。

原文由 luso 发布,翻译遵循 CC BY-SA 4.0 许可协议

阅读 747
2 个回答

基本理念


第一个选项是定义错误对象并将它们作为 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"
}

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

引入异常层次结构


如果您正在创建一个 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"
}

原文由 Ali Dehghani 发布,翻译遵循 CC BY-SA 4.0 许可协议

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

@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);
}

原文由 AbdusSalam 发布,翻译遵循 CC BY-SA 3.0 许可协议

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题