将正文添加到 404 Not Found 异常

Posted

技术标签:

【中文标题】将正文添加到 404 Not Found 异常【英文标题】:Add a body to a 404 Not Found Exception 【发布时间】: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? 但我无法设置响应的参数。

【问题讨论】:

【参考方案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

以上是关于将正文添加到 404 Not Found 异常的主要内容,如果未能解决你的问题,请参考以下文章

将 gitlab 与 jenkins 集成时 404 Not found

python异常处理时报错,提示:HTTPError: HTTP Error 404: Not Found

Django Media url 返回 404 NOT FOUND

命令引发异常:NotFound: 404 Not Found (error code: 0): Interaction is unknown (你已经响应了交互)

将 403 Forbidden 重定向到 404 Not Found 时出现问题

将所有 Apache 2.2 403 Forbidden 重定向到 404 Not Found