มีหลายกรณีการใช้งานสำหรับการตั้งค่ารหัสสถานะ HTTP ในบริการเว็บ REST และอย่างน้อยหนึ่งรายการไม่ได้รับการบันทึกไว้อย่างเพียงพอในคำตอบที่มีอยู่ (เช่นเมื่อคุณกำลังใช้การจัดลำดับ JSON / XML อัตโนมัติ - เวทมนต์โดยใช้ JAXB และคุณต้องการส่งคืน วัตถุที่จะต่อเนื่อง แต่ยังรหัสสถานะที่แตกต่างจาก 200 เริ่มต้น)
ดังนั้นฉันจะลองและแจกแจงกรณีการใช้งานที่แตกต่างกันและวิธีแก้ปัญหาสำหรับแต่ละกรณี:
1. รหัสข้อผิดพลาด (500, 404, ... )
กรณีการใช้งานที่พบบ่อยที่สุดเมื่อคุณต้องการส่งคืนรหัสสถานะที่แตกต่างจาก200 OK
เมื่อเกิดข้อผิดพลาด
ตัวอย่างเช่น:
- มีการร้องขอเอนทิตี แต่ไม่มีอยู่ (404)
- คำขอไม่ถูกต้องเชิงความหมาย (400)
- ผู้ใช้ไม่ได้รับอนุญาต (401)
- มีปัญหากับการเชื่อมต่อฐานข้อมูล (500)
- ฯลฯ ..
a) โยนข้อยกเว้น
ในกรณีนี้ฉันคิดว่าวิธีที่สะอาดที่สุดในการจัดการปัญหาคือการยกเว้น ข้อยกเว้นนี้จะได้รับการจัดการโดยExceptionMapper
ที่จะแปลข้อยกเว้นเป็นการตอบกลับด้วยรหัสข้อผิดพลาดที่เหมาะสม
คุณสามารถใช้ค่าเริ่มต้นExceptionMapper
ที่มาก่อนกำหนดที่มีย์ (และผมคิดว่ามันเป็นเรื่องเดียวกันกับการใช้งานอื่น ๆ ) และโยนใด ๆ javax.ws.rs.WebApplicationException
ของที่มีอยู่ย่อยชั้นเรียนของ เหล่านี้เป็นประเภทข้อยกเว้นที่กำหนดไว้ล่วงหน้าที่แมปล่วงหน้าไปยังรหัสข้อผิดพลาดที่แตกต่างกันตัวอย่างเช่น:
- BadRequestException (400)
- InternalServerErrorException (500)
- NotFoundException (404)
เป็นต้นคุณสามารถค้นหารายการได้ที่นี่: API
อีกทางหนึ่งคุณสามารถกำหนดข้อยกเว้นและExceptionMapper
คลาสที่กำหนดเองของคุณเองและเพิ่มตัวแม็พเหล่านี้ไปยัง Jersey ด้วยค่าเฉลี่ยของ@Provider
หมายเหตุประกอบ ( แหล่งที่มาของตัวอย่างนี้ ):
public class MyApplicationException extends Exception implements Serializable
{
private static final long serialVersionUID = 1L;
public MyApplicationException() {
super();
}
public MyApplicationException(String msg) {
super(msg);
}
public MyApplicationException(String msg, Exception e) {
super(msg, e);
}
}
ผู้ให้บริการ :
@Provider
public class MyApplicationExceptionHandler implements ExceptionMapper<MyApplicationException>
{
@Override
public Response toResponse(MyApplicationException exception)
{
return Response.status(Status.BAD_REQUEST).entity(exception.getMessage()).build();
}
}
หมายเหตุ: คุณยังสามารถเขียน ExceptionMappers สำหรับประเภทข้อยกเว้นที่มีอยู่ที่คุณใช้
b) ใช้เครื่องมือสร้างการตอบสนอง
อีกวิธีในการตั้งค่ารหัสสถานะคือการใช้ตัวResponse
สร้างเพื่อสร้างการตอบกลับด้วยรหัสที่ต้องการ
javax.ws.rs.core.Response
ในกรณีที่ประเภทกลับวิธีการของคุณต้องเป็น นี่คือคำอธิบายในการตอบกลับอื่น ๆ เช่นคำตอบที่ยอมรับได้ของเขาและดูเหมือนว่า:
@GET
@Path("myresource({id}")
public Response retrieveSomething(@PathParam("id") String id) {
...
Entity entity = service.getById(uuid);
if(entity == null) {
return Response.status(Response.Status.NOT_FOUND).entity("Resource not found for ID: " + uuid).build();
}
...
}
2. สำเร็จ แต่ไม่ใช่ 200
อีกกรณีที่คุณต้องการตั้งค่าสถานะการส่งคืนคือเมื่อการดำเนินการประสบความสำเร็จ แต่คุณต้องการส่งคืนรหัสความสำเร็จที่แตกต่างจาก 200 พร้อมกับเนื้อหาที่คุณส่งคืนในเนื้อความ
กรณีใช้งานบ่อยคือเมื่อคุณสร้างเอนทิตีใหม่ ( POST
คำขอ) และต้องการส่งคืนข้อมูลเกี่ยวกับเอนทิตีใหม่นี้หรืออาจเป็นเอนทิตีเองพร้อมกับ201 Created
รหัสสถานะ
วิธีหนึ่งคือการใช้วัตถุตอบสนองเช่นเดียวกับที่อธิบายไว้ข้างต้นและตั้งค่าเนื้อหาของคำขอด้วยตนเอง อย่างไรก็ตามการทำเช่นนี้ทำให้คุณไม่สามารถใช้การจัดลำดับอัตโนมัติเป็น XML หรือ JSON ที่ JAXB จัดหาให้
นี่เป็นวิธีการดั้งเดิมที่ส่งคืนวัตถุเอนทิตีที่จะถูกทำให้เป็นอนุกรมกับ JSON โดย JAXB:
@Path("/")
@POST
@Consumes({ MediaType.APPLICATION_JSON })
@Produces({ MediaType.APPLICATION_JSON })
public User addUser(User user){
User newuser = ... do something like DB insert ...
return newuser;
}
สิ่งนี้จะส่งคืนการแสดง JSON ของผู้ใช้ที่สร้างขึ้นใหม่ แต่สถานะการส่งคืนจะเป็น 200 ไม่ใช่ 201
ตอนนี้ปัญหาคือถ้าฉันต้องการใช้ตัวResponse
สร้างเพื่อตั้งรหัสส่งคืนฉันต้องส่งคืนResponse
วัตถุในวิธีการของฉัน ฉันจะกลับยังไงUser
วัตถุให้เป็นอนุกรมได้อย่างไร
a) ตั้งรหัสบนการตอบสนองของเซิร์ฟเล็ต
วิธีหนึ่งในการแก้ปัญหานี้คือการขอรับวัตถุคำขอ servlet และตั้งรหัสการตอบสนองด้วยตนเองเช่นแสดงในคำตอบของ Garett Wilson
@Path("/")
@POST
@Consumes({ MediaType.APPLICATION_JSON })
@Produces({ MediaType.APPLICATION_JSON })
public User addUser(User user, @Context final HttpServletResponse response){
User newUser = ...
//set HTTP code to "201 Created"
response.setStatus(HttpServletResponse.SC_CREATED);
try {
response.flushBuffer();
}catch(Exception e){}
return newUser;
}
วิธีการยังคงส่งคืนวัตถุนิติบุคคลและรหัสสถานะจะเป็น 201
โปรดทราบว่าเพื่อให้มันทำงานได้ฉันต้องล้างการตอบสนอง นี่คือการฟื้นตัวที่ไม่พึงประสงค์ของรหัส Servlet API ระดับต่ำในแหล่งข้อมูล JAX_RS ที่ดีของเราและที่แย่กว่านั้นคือทำให้ส่วนหัวไม่สามารถแก้ไขได้หลังจากสิ่งนี้เพราะพวกเขาถูกส่งไปที่สายแล้ว
b) ใช้ออบเจคการตอบสนองกับเอนทิตี
ทางออกที่ดีที่สุดในกรณีนั้นคือการใช้การตอบสนองวัตถุและตั้งเอนทิตีที่จะต่อเนื่องกันบนวัตถุการตอบสนองนี้ มันเป็นการดีที่จะทำให้การตอบสนองวัตถุทั่วไปเพื่อระบุประเภทของหน่วยงานที่บรรจุในกรณีนั้น แต่ไม่ได้เป็นกรณีในปัจจุบัน
@Path("/")
@POST
@Consumes({ MediaType.APPLICATION_JSON })
@Produces({ MediaType.APPLICATION_JSON })
public Response addUser(User user){
User newUser = ...
return Response.created(hateoas.buildLinkUri(newUser, "entity")).entity(restResponse).build();
}
ในกรณีนี้เราใช้วิธีการสร้างของคลาส Response builder เพื่อตั้งรหัสสถานะเป็น 201 เราส่งวัตถุเอนทิตี (ผู้ใช้) ไปยังการตอบกลับผ่านเมธอดเอนทิตี้ ()
ผลลัพธ์ก็คือรหัส HTTP คือ 401 ตามที่เราต้องการและเนื้อความของการตอบสนองเป็น JSON เดียวกับที่เราเคยมีมาก่อนเมื่อเราเพิ่งคืนค่าวัตถุผู้ใช้ นอกจากนี้ยังเพิ่มส่วนหัวสถานที่ตั้ง
คลาส Response มีจำนวนวิธีการสร้างสำหรับสถานะที่แตกต่าง (stati?) เช่น:
Response.accepted () Response.ok () Response.noContent () Response.notAcceptable ()
หมายเหตุ: วัตถุเกลียดชังเป็นคลาสผู้ช่วยที่ฉันพัฒนาขึ้นเพื่อช่วยสร้าง URI ของทรัพยากร คุณจะต้องมีกลไกของคุณเองที่นี่;)
เกี่ยวกับมัน.
ฉันหวังว่าการตอบสนองที่ยาวนานนี้จะช่วยใครซักคน :)