在冲突(409)响应中添加JpaRepository中的冲突实体

时间:2015-07-27 15:28:20

标签: spring spring-boot spring-data-rest

当某个客户端尝试POST数据库中的重复实体时,Spring Data REST返回409状态代码和JSON异常体。

JpaRepository

@RepositoryRestResource
@PreAuthorize(whoCanPostAndUpdateTheirMessages)
public interface MessageRepository extends JpaRepository<Message, Long> {

}

请求

curl -u $AUTH -X POST -H "Content-Type:application/json" -d '{ "patient": "'$PATIENT_URL'", "date": "2014-01-01T00:00:0", "device": "00:00:00:00:00", "body": "this is a message" }' $SERVER/messages

响应

HTTP/1.1 409 Conflict
{
  "cause" : {
    "cause" : {
      "cause" : null,
      "message" : "ERROR: duplicate key value violates unique constraint \"uk_ofdr0s8f4x6q22veekngtwifd\"\n  Detail: Key (date, device)=(2014-01-01 00:00:00, 00:00:00:00:00) already exists."
    },
    "message" : "could not execute statement"
  },
  "message" : "could not execute statement; SQL [n/a]; constraint [uk_ofdr0s8f4x6q22veekngtwifd]; nested exception is org.hibernate.exception.ConstraintViolationException: could not execute statement"

是否可以在响应正文中包含冲突实体(ID / URI),以便客户端知道稍后在该资源上执行PUT / PATCH的位置?

2 个答案:

答案 0 :(得分:1)

我建议传回资源uri位置标题

@RequestMapping(value="/create",method=RequestMethod.GET)
public ResponseEntity<?> create(@Valid Entity purchase ,BindingResult result){
    boolean exits= false;
    // you checks here
    if(exits){
        return ResponseEntity.status(HttpStatus.CONFLICT).header(HttpHeaders.LOCATION, "http://resource/id").build();
    }

    return ResponseEntity.created(new URI("http://resource/id")).build();

}

答案 1 :(得分:1)

TL;博士

使用服务器端验证手段来检测潜在的冲突(例如重复的用户名或电子邮件地址),并抛出一个有意义的异常,转换为体面的状态代码和消息。

一般情况下,如果没有必要,请不要向客户透露相关信息,因为这可能会成为攻击者利用的安全风险。

详细

我不认为在此处返回POST请求的其他信息是个好主意,因为您可能会在尝试创建实体时泄露有关现有实体的敏感信息。

在创建时,所有可能存在冲突的属性都应该通过服务器上的专用方式进行验证(即,如果它是使用相应事件和/或验证器的Spring Data REST),那么您实际上可以抛出适当的异常。如果您将无效数据流入您的数据库,您基本上无法获得有关哪个其他实体导致冲突的任何进一步信息。这基本上是将无效数据传递到整个应用程序堆栈的副作用,这不应该首先发生。

如果调用返回了有关现有实体的信息,则可以使用它来窥探其标识符(例如,尝试通过创建具有已知用户名的实体来查找已存在实体的ID)。对于PUTPATCH请求,这略有不同,因为客户端已经知道首先发出请求的标识符。