【问题标题】:Spring Boot Rest Controller how to return different HTTP status codes?Spring Boot Rest Controller 如何返回不同的 HTTP 状态码?
【发布时间】:2014-08-09 03:38:30
【问题描述】:

我正在将 Spring Boot 用于简单的 REST API,如果出现故障,我希望返回正确的 HTTP 状态码。

@RequestMapping(value="/rawdata/", method = RequestMethod.PUT)
@ResponseBody
@ResponseStatus( HttpStatus.OK )
public RestModel create(@RequestBody String data) {
    // code ommitted..
    // how do i return a correct status code if something fails?
}

作为 Spring 和 Spring Boot 的新手,基本问题是当事情正常或失败时如何返回不同的状态码?

【问题讨论】:

    标签: spring rest spring-boot


    【解决方案1】:

    您可以使用多种选项。相当好的方法是使用异常和类进行处理,称为@ControllerAdvice

    @ControllerAdvice
    class GlobalControllerExceptionHandler {
        @ResponseStatus(HttpStatus.CONFLICT)  // 409
        @ExceptionHandler(DataIntegrityViolationException.class)
        public void handleConflict() {
            // Nothing to do
        }
    }
    

    您也可以将HttpServletResponse 传递给控制器​​方法并设置响应代码:

    public RestModel create(@RequestBody String data, HttpServletResponse response) {
        // response committed...
        response.setStatus(HttpServletResponse.SC_ACCEPTED);
    }
    

    详情请参阅这篇精彩的博文:Exception Handling in Spring MVC


    注意

    在 Spring MVC 中使用 @ResponseBody 注释是多余的 - 它已经包含在 @RestController 注释中。

    【讨论】:

    • 就像评论一样,我在 15 分钟前做了一个测试,在他的方法上没有“@ResponseBody”注释的“@RestController”将返回的字符串不是在正文中,而是作为 ForwardedURL。我对自己的 spring/springboot 非常陌生,所以无法指出原因
    • @Anearion 答案中有一个错字——我们实际上需要'@RestControllerAdvice',而不是'@RestController'。
    • 这不是错字。这部分与控制器上的问题和注释有关
    • 请注意,javax.servlet.http.HttpServletResponse 似乎没有org.springframework.http.HttpStatus 拥有的所有状态代码。所以你可以使用HttpStatus.UNPROCESSABLE_ENTITY.value() 将int-value 传递给response.setStatus。 另外这非常适合使用@ExceptionHandler 进行错误处理。
    【解决方案2】:

    其中一种方法是您可以使用 ResponseEntity 作为返回对象。

    @RequestMapping(value="/rawdata/", method = RequestMethod.PUT)
    
    public ResponseEntity<?> create(@RequestBody String data) {
        if(everything_fine) {
            return new ResponseEntity<>(RestModel, HttpStatus.OK);
        } else {
            return new ResponseEntity<>(null, HttpStatus.INTERNAL_SERVER_ERROR);
        }
    }
    

    【讨论】:

    • Spring以后版本不需要使用null:new ResponseEntity(HttpStatus.NOT_FOUND)
    【解决方案3】:

    一个不错的方法是使用 Spring 的ResponseStatusException

    而不是返回 ResponseEntity 或类似的,您只需使用 HttpStatus 从控制器中抛出 ResponseStatusException 并导致,例如:

    throw new ResponseStatusException(HttpStatus.BAD_REQUEST, "Cause description here");
    

    这会导致对包含 HTTP 状态的客户端的响应:

    {
      "timestamp": "2020-07-09T04:43:04.695+0000",
      "status": 400,
      "error": "Bad Request",
      "message": "Cause description here",
      "path": "/test-api/v1/search"
    }
    

    注意HttpStatus 提供了许多不同的状态码以方便您使用。

    【讨论】:

    • 简单、干净且可通过 REST 客户端使用。
    【解决方案4】:

    如果你想返回一个自定义的状态码,你可以在这里使用 ResponseEntity:

    @RequestMapping(value="/rawdata/", method = RequestMethod.PUT)
    public ResponseEntity<?> create(@RequestBody String data) {
        int customHttpStatusValue = 499;
        Foo foo = bar();
        return ResponseEntity.status(customHttpStatusValue).body(foo);
    }
    

    CustomHttpStatusValue 可以是标准 HTTP 状态代码之内或之外的任何整数。

    【讨论】:

    • 我喜欢这种流畅的 API 方法。
    【解决方案5】:

    试试这个代码:

    @RequestMapping(value = "/validate", method = RequestMethod.GET, produces = "application/json")
    public ResponseEntity<ErrorBean> validateUser(@QueryParam("jsonInput") final String jsonInput) {
        int numberHTTPDesired = 400;
        ErrorBean responseBean = new ErrorBean();
        responseBean.setError("ERROR");
        responseBean.setMensaje("Error in validation!");
    
        return new ResponseEntity<ErrorBean>(responseBean, HttpStatus.valueOf(numberHTTPDesired));
    }
    

    【讨论】:

    • 因为这是一个相当老的问题,所以你应该添加你所引用的包和版本信息。
    • 你能包含ErrorBean的示例实现吗?
    【解决方案6】:

    返回状态码有多种方式, 1 : RestController 类应该扩展 BaseRest 类,在 BaseRest 类中我们可以处理异常并返回预期的错误代码。 例如:

    @RestController
    @RequestMapping
    class RestController extends BaseRest{
    
    }
    
    @ControllerAdvice
    public class BaseRest {
    @ExceptionHandler({Exception.class,...})
        @ResponseStatus(value=HttpStatus.INTERNAL_SERVER_ERROR)
        public ErrorModel genericError(HttpServletRequest request, 
                HttpServletResponse response, Exception exception) {
            
            ErrorModel error = new ErrorModel();
            resource.addError("error code", exception.getLocalizedMessage());
            return error;
        }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2020-10-25
      • 1970-01-01
      • 2014-07-23
      • 2017-02-25
      • 2019-09-26
      • 1970-01-01
      • 1970-01-01
      • 2020-10-07
      相关资源
      最近更新 更多