Spring Boot Rest Controller làm thế nào để trả về các mã trạng thái HTTP khác nhau?


102

Tôi đang sử dụng Spring Boot cho một API REST đơn giản và muốn trả lại mã trạng thái HTTP chính xác nếu có sự cố.

@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?
}

Mới sử dụng Spring và Spring Boot, câu hỏi cơ bản là làm cách nào để trả lại các mã trạng thái khác nhau khi có điều gì đó ổn hoặc không thành công?

Câu trả lời:


117

Có một số tùy chọn bạn có thể sử dụng. Cách khá tốt là sử dụng các ngoại lệ và lớp để xử lý được gọi là @ControllerAdvice:

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

Ngoài ra, bạn có thể chuyển HttpServletResponseđến phương thức điều khiển và chỉ cần đặt mã phản hồi:

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

Vui lòng tham khảo bài đăng blog tuyệt vời này để biết chi tiết: Xử lý ngoại lệ trong Spring MVC


GHI CHÚ

Trong Spring MVC, sử dụng @ResponseBodychú thích là không cần thiết - nó đã được đưa vào @RestControllerchú thích.


Cũng giống như nhận xét, tôi đã thực hiện một bài kiểm tra 15 phút trước và một '@RestController' không có chú thích '@ResponseBody' trên phương thức của anh ấy đã đặt chuỗi được trả về không phải bên trong phần thân mà là ForwardedURL. Tôi Noob khá với mùa xuân / springboot tự của tôi vì vậy không thể chỉ ra lý do tại sao
Anearion

@Anearion Có một lỗi đánh máy trong câu trả lời - chúng tôi thực sự cần '@RestControllerAdvice', không phải '@RestController'.
yoliho

Nó không phải là lỗi đánh máy. Phần này có liên quan đến câu hỏi và chú thích trên một bộ điều khiển
Jakub Kubrynski

1
Lưu ý, điều đó javax.servlet.http.HttpServletResponsedường như không có tất cả các Mã trạng thái org.springframework.http.HttpStatus. Vì vậy, bạn có thể sử dụng HttpStatus.UNPROCESSABLE_ENTITY.value()để chuyển giá trị int vào response.setStatus. Ngoài ra, điều này hoàn toàn hoạt động để xử lý lỗi khi sử dụng @ExceptionHandler.
Igor

43

Một trong những cách để làm điều này là bạn có thể sử dụng ResponseEntity làm đối tượng trả về.

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

}

3
Không cần sử dụng null trong các phiên bản sau của Spring: new ResponseEntity <> (HttpStatus.NOT_FOUND)
Kong

4

Hãy thử mã này:

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

Vì đây là một câu hỏi khá cũ, vì vậy bạn nên thêm thông tin gói và phiên bản mà bạn tham khảo.
ZF007

Bạn có thể bao gồm một triển khai ví dụ của ErrorBean?
Brent Bradburn

3

Một cách hay là sử dụng Spring's ResponseStatusException

Thay vì trả về một ResponseEntityhoặc tương tự, bạn chỉ cần ném ResponseStatusExceptiontừ bộ điều khiển với một HttpStatusvà nguyên nhân, ví dụ:

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

hoặc là:

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

Điều này dẫn đến phản hồi cho ứng dụng khách có trạng thái HTTP (ví dụ: 400 Yêu cầu không hợp lệ) với nội dung như:

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

2

Trong trường hợp bạn muốn trả về mã trạng thái được xác định tùy chỉnh, bạn có thể sử dụng ResponseEntity như sau:

@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 có thể là bất kỳ số nguyên nào bên trong hoặc bên ngoài Mã trạng thái HTTP tiêu chuẩn.


Tôi thích cách tiếp cận API thông thạo này.
v.ladynev

0

Có nhiều cách khác nhau để trả về mã trạng thái, 1: Lớp RestController nên mở rộng lớp BaseRest, trong lớp BaseRest chúng ta có thể xử lý ngoại lệ và trả về mã lỗi mong đợi. ví dụ :

@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;
    }
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.