Spring Boot Rest Controller จะส่งคืนรหัสสถานะ HTTP ต่างกันอย่างไร


104

ฉันใช้ 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 คำถามพื้นฐานคือฉันจะส่งคืนรหัสสถานะต่างๆได้อย่างไรเมื่อมีบางอย่างตกลงหรือล้มเหลว

คำตอบ:


120

มีหลายตัวเลือกที่คุณสามารถใช้ได้ วิธีที่ดีคือใช้ข้อยกเว้นและคลาสสำหรับการจัดการที่เรียกว่า@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);
}

โปรดดูรายละเอียดในบล็อกโพสต์ที่ยอดเยี่ยมนี้: การจัดการข้อยกเว้นใน Spring MVC


บันทึก

ใน Spring MVC ที่ใช้@ResponseBodyคำอธิบายประกอบนั้นซ้ำซ้อนซึ่งรวมอยู่ใน@RestControllerคำอธิบายประกอบแล้ว


เช่นเดียวกับความคิดเห็นฉันได้ทำการทดสอบเมื่อ 15 นาทีที่แล้วและ '@RestController' โดยไม่มีคำอธิบายประกอบ '@ResponseBody' เหนือวิธีการของเขาทำให้สตริงที่ส่งคืนไม่ได้อยู่ในร่างกาย แต่เป็น ForwardedURL ฉันสวย noob กับฤดูใบไม้ผลิ / ฤดูใบไม้ผลิตัวเองดังนั้นไม่สามารถชี้ให้เห็นว่าทำไม
Anearion

@Anearion มีคำตอบที่พิมพ์ผิด - จริงๆแล้วเราต้องการ '@RestControllerAdvice' ไม่ใช่ '@RestController'
yoliho

มันไม่ได้พิมพ์ผิด ส่วนนี้เกี่ยวข้องกับคำถามและคำอธิบายประกอบบนคอนโทรลเลอร์
Jakub Kubrynski

1
หมายเหตุที่javax.servlet.http.HttpServletResponseดูเหมือนว่าจะไม่ได้มี StatusCodes ทั้งหมดที่org.springframework.http.HttpStatusไม่ ดังนั้นคุณสามารถใช้HttpStatus.UNPROCESSABLE_ENTITY.value()เพื่อส่งค่า int ไปยัง response.setStatus นอกจาก@ExceptionHandlerนี้ทำงานอย่างสมบูรณ์แบบสำหรับข้อผิดพลาดในการจัดการการใช้
Igor

43

วิธีหนึ่งในการทำเช่นนี้คือคุณสามารถใช้ 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);

}

3
ไม่จำเป็นต้องใช้โมฆะใน Spring: new ResponseEntity <> (HttpStatus.NOT_FOUND)
Kong

4

ลองใช้รหัสนี้:

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

เนื่องจากนี่เป็นคำถามที่ค่อนข้างเก่าดังนั้นคุณควรเพิ่มข้อมูลแพ็คเกจและเวอร์ชันที่คุณอ้างถึง
ZF007

คุณสามารถรวมตัวอย่างการใช้งานได้ErrorBeanหรือไม่?
Brent Bradburn

4

วิธีที่ดีคือใช้ResponseStatusExceptionของ Spring

แทนที่จะส่งคืนResponseEntityหรือสิ่งที่คล้ายกันคุณเพียงแค่โยนResponseStatusExceptionจากคอนโทรลเลอร์ด้วยHttpStatusและสาเหตุตัวอย่างเช่น:

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

หรือ:

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

ส่งผลให้เกิดการตอบสนองต่อไคลเอ็นต์ที่มีสถานะ HTTP (เช่น 400 คำขอไม่ถูกต้อง) โดยมีเนื้อหาดังนี้:

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

ง่ายสะอาดและสิ้นเปลืองโดยไคลเอนต์ REST
Alecz

3

ในกรณีที่คุณต้องการส่งคืนรหัสสถานะที่กำหนดเองคุณสามารถใช้ 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 ที่คล่องแคล่วนี้
v.ladynev

0

มีหลายวิธีในการส่งคืนรหัสสถานะ 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;
    }
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.