我正在构建一个允许客户端存储对象的服务器。这些对象是在客户端完全构造的,对象id在对象的整个生命周期内都是永久的。
我已经定义了API,以便客户端可以使用PUT创建或修改对象:
PUT /objects/{id} HTTP/1.1
...
{json representation of the object}
{id}是对象id,所以它是Request-URI的一部分。
现在,我也在考虑允许客户端使用POST创建对象:
POST /objects/ HTTP/1.1
...
{json representation of the object, including ID}
由于POST意味着“追加”操作,我不确定在对象已经存在的情况下该做什么。我应该把请求作为修改请求,还是应该返回一些错误代码(哪个)?
我会选择422不可处理实体,当请求无效时使用,但问题不在于语法或身份验证。
作为反对其他答案的论据,使用任何非4xx错误代码将暗示它不是客户端错误,而它显然是。使用非4xx错误代码来表示客户端错误完全没有意义。
It seems that 409 Conflict is the most common answer here, but, according to the spec, that implies that the resource already exists and the new data you are applying to it is incompatible with its current state. If you are sending a POST request, with, for example, a username that is already taken, it's not actually conflicting with the target resource, as the target resource (the resource you're trying to create) has not yet been posted. It's an error specifically for version control, when there is a conflict between the version of the resource stored and the version of the resource requested. It's very useful for that purpose, for example when the client has cached an old version of the resource and sends a request based on that incorrect version which would no longer be conditionally valid. "In this case, the response representation would likely contain information useful for merging the differences based on the revision history." The request to create another user with that username is just unprocessable, having nothing to do with any version conflict.
为了记录,422也是GitHub使用的状态码,当您尝试按已使用的名称创建存储库时。
“302 Found”对我来说听起来合乎逻辑。RFC 2616说除了GET和HEAD之外,它还可以被其他请求回答(当然也包括POST)
但是它仍然让访问者通过RFC访问这个URL来获得这个“已找到”的资源。为了使它直接指向真正的“Found”URL,应该使用“303 See Other”,这是有意义的,但强制另一个调用GET它后面的URL。好的方面是,这个GET是可缓存的。
我想我会用“303 See Other”。我不知道我是否可以响应在主体中发现的“东西”,但我想这样做,以节省到服务器的一次往返。
更新:在重新阅读RFC后,我仍然认为不存在的“4XX+303 Found”代码应该是正确的。然而,“409冲突”是现有的最好的答案代码(正如@ wrkken指出的那样),可能包括指向现有资源的Location头。
I think for REST, you just have to make a decision on the behavior for that particular system in which case, I think the "right" answer would be one of a couple answers given here. If you want the request to stop and behave as if the client made a mistake that it needs to fix before continuing, then use 409. If the conflict really isn't that important and want to keep the request going, then respond by redirecting the client to the entity that was found. I think proper REST APIs should be redirecting (or at least providing the location header) to the GET endpoint for that resource following a POST anyway, so this behavior would give a consistent experience.
EDIT:
It's also worth noting that you should consider a PUT since you're providing the ID. Then the behavior is simple: "I don't care what's there right now, put this thing there." Meaning, if nothing is there, it'll be created; if something is there it'll be replaced. I think a POST is more appropriate when the server manages that ID. Separating the two concepts basically tells you how to deal with it (i.e. PUT is idempotent so it should always work so long as the payload validates, POST always creates, so if there is a collision of IDs, then a 409 would describe that conflict).
我会选择422不可处理实体,当请求无效时使用,但问题不在于语法或身份验证。
作为反对其他答案的论据,使用任何非4xx错误代码将暗示它不是客户端错误,而它显然是。使用非4xx错误代码来表示客户端错误完全没有意义。
It seems that 409 Conflict is the most common answer here, but, according to the spec, that implies that the resource already exists and the new data you are applying to it is incompatible with its current state. If you are sending a POST request, with, for example, a username that is already taken, it's not actually conflicting with the target resource, as the target resource (the resource you're trying to create) has not yet been posted. It's an error specifically for version control, when there is a conflict between the version of the resource stored and the version of the resource requested. It's very useful for that purpose, for example when the client has cached an old version of the resource and sends a request based on that incorrect version which would no longer be conditionally valid. "In this case, the response representation would likely contain information useful for merging the differences based on the revision history." The request to create another user with that username is just unprocessable, having nothing to do with any version conflict.
为了记录,422也是GitHub使用的状态码,当您尝试按已使用的名称创建存储库时。