Spring Boot Rest Controller bagaimana cara mengembalikan kode status HTTP yang berbeda?


102

Saya menggunakan Spring Boot untuk REST API sederhana dan ingin mengembalikan kode status HTTP yang benar jika ada yang gagal.

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

Menjadi baru di Spring dan Spring Boot, pertanyaan dasarnya adalah bagaimana cara mengembalikan kode status yang berbeda ketika ada sesuatu yang baik atau gagal?

Jawaban:


118

Ada beberapa opsi yang bisa Anda gunakan. Cara yang cukup baik adalah dengan menggunakan pengecualian dan kelas untuk penanganan yang disebut @ControllerAdvice:

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

Anda juga dapat meneruskan HttpServletResponseke metode pengontrol dan hanya mengatur kode respons:

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

Silakan merujuk ke posting blog hebat ini untuk detailnya: Penanganan Pengecualian di MVC Musim Semi


CATATAN

Di Musim Semi MVC menggunakan @ResponseBodyanotasi adalah mubazir - itu sudah termasuk dalam @RestControlleranotasi.


Sama seperti komentar, saya melakukan tes 15 menit yang lalu, dan '@RestController' tanpa anotasi '@ResponseBody' atas metodenya menempatkan string yang dikembalikan bukan di dalam tubuh tetapi sebagai ForwardedURL. Saya cukup pemula dengan musim semi /
sepatu

@Anearion Ada kesalahan ketik dalam jawabannya - kami sebenarnya membutuhkan '@RestControllerAdvice', bukan '@RestController'.
yoliho

Ini bukan salah ketik. Bagian ini terkait dengan pertanyaan dan penjelasan pada pengontrol
Jakub Kubrynski

1
Catatan, javax.servlet.http.HttpServletResponsetampaknya tidak semua Kode Status org.springframework.http.HttpStatusmemiliki. Jadi, Anda bisa menggunakan HttpStatus.UNPROCESSABLE_ENTITY.value()untuk meneruskan nilai int ke response.setStatus. Ini juga berfungsi dengan sempurna untuk penanganan kesalahan @ExceptionHandler.
Igor

43

Salah satu cara untuk melakukannya adalah Anda dapat menggunakan ResponseEntity sebagai objek pengembalian.

@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
Tidak perlu menggunakan null di versi Spring: new ResponseEntity <> (HttpStatus.NOT_FOUND)
Kong

4

Coba kode ini:

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

Karena ini adalah pertanyaan yang agak lama maka Anda harus menambahkan info paket dan versi yang Anda rujuk.
ZF007

Bisakah Anda menyertakan contoh implementasi ErrorBean?
Brent Bradburn

4

Cara yang bagus adalah dengan menggunakan ResponseStatusException dari Spring

Daripada mengembalikan ResponseEntityatau serupa, Anda cukup membuang ResponseStatusExceptiondari pengontrol dengan HttpStatusdan sebab, misalnya:

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

atau:

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

Ini menghasilkan respons ke klien yang berisi status HTTP (mis. 400 Permintaan buruk) dengan isi seperti:

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

Sederhana, bersih, dan dapat dikonsumsi oleh klien REST.
Alecz

2

Jika Anda ingin mengembalikan kode status yang ditentukan khusus, Anda dapat menggunakan ResponseEntity seperti di sini:

@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 bisa berupa bilangan bulat apa pun di dalam atau di luar Kode Status HTTP standar.


Saya suka pendekatan API yang lancar ini.
v.ladynev

0

Ada berbagai cara untuk mengembalikan kode status, 1: Kelas RestController harus memperluas kelas BaseRest, di kelas BaseRest kita dapat menangani pengecualian dan mengembalikan kode kesalahan yang diharapkan. sebagai contoh :

@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;
    }
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.