我正在构建一个允许客户端存储对象的服务器。这些对象是在客户端完全构造的,对象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意味着“追加”操作,我不确定在对象已经存在的情况下该做什么。我应该把请求作为修改请求,还是应该返回一些错误代码(哪个)?


当前回答

错误402,需要付款

例如,这个资源已经存在,但如果你给我足够的钱,我会删除当前的一个,给你:D

...但是看看mozilla在https://developer.mozilla.org/en-US/docs/Web/HTTP/Status#client_error_responses上对状态码的定义

作为一个更严肃的答案,这里没有人提供,那451呢:由于法律原因无法使用。你不能“合法地(通过你自己制定的条款和条件)”让多人访问相同的帐户信息

422也是一个很好的选择,它是不可处理的实体 请求格式良好,但由于语义错误而无法执行。由于它是一个完全有效的请求,但由于它在语义上与另一个条目相等,所以不能遵循它。

其他回答

在您的情况下,您可以使用409冲突

如果你想检查另一个HTTPs状态码从下面的列表

1××信息

100 Continue
101 Switching Protocols
102 Processing

2××成功

200 OK
201 Created
202 Accepted
203 Non-authoritative Information
204 No Content
205 Reset Content
206 Partial Content
207 Multi-Status
208 Already Reported
226 IM Used

3××重定向

300 Multiple Choices
301 Moved Permanently
302 Found
303 See Other
304 Not Modified
305 Use Proxy
307 Temporary Redirect
308 Permanent Redirect

4××客户端错误

400 Bad Request
401 Unauthorized
402 Payment Required
403 Forbidden
404 Not Found
405 Method Not Allowed
406 Not Acceptable
407 Proxy Authentication Required
408 Request Timeout
409 Conflict
410 Gone
411 Length Required
412 Precondition Failed
413 Payload Too Large
414 Request-URI Too Long
415 Unsupported Media Type
416 Requested Range Not Satisfiable
417 Expectation Failed
418 I’m a teapot
421 Misdirected Request
422 Unprocessable Entity
423 Locked
424 Failed Dependency
426 Upgrade Required
428 Precondition Required
429 Too Many Requests
431 Request Header Fields Too Large
444 Connection Closed Without Response
451 Unavailable For Legal Reasons
499 Client Closed Request

5××服务器错误

500 Internal Server Error
501 Not Implemented
502 Bad Gateway
503 Service Unavailable
504 Gateway Timeout
505 HTTP Version Not Supported
506 Variant Also Negotiates
507 Insufficient Storage
508 Loop Detected
510 Not Extended
511 Network Authentication Required
599 Network Connect Timeout Error

就我个人而言,我倾向于WebDAV扩展422不可处理实体。

根据RFC 4918

422不可处理实体状态码意味着服务器理解请求实体的内容类型(因此415不支持的媒体类型状态码是不合适的),并且请求实体的语法是正确的(因此400坏请求状态码是不合适的),但无法处理包含的指令。

也许是在游戏后期,但我在尝试创建REST API时偶然发现了这个语义问题。

为了稍微扩展一下wrkken的回答,我认为您可以根据情况使用409 Conflict或403 Forbidden -简而言之,当用户完全无法解决冲突并完成请求时使用403错误(例如,他们不能发送DELETE请求来显式删除资源),或者如果可能做一些事情,则使用409。

10.4.4禁止403 服务器理解请求,但拒绝执行。 授权没有帮助,请求不应该重复。如果 请求方法不是HEAD,服务器希望公开 为什么要求没有被满足,它应该描述原因 对于实体中的拒绝。如果服务器不希望做出 此信息可用于客户端,状态代码404(不是 Found)可以代替。

现在,有人说“403”,就会想到权限或身份验证问题,但规范说,这基本上是服务器告诉客户端它不会这样做,不要再问了,这就是客户端不应该这样做的原因。

至于PUT vs. POST…当用户没有办法或不应该为资源创建标识符时,POST应该用于创建资源的新实例。当资源的标识已知时,使用PUT。

9.6 PUT ... The fundamental difference between the POST and PUT requests is reflected in the different meaning of the Request-URI. The URI in a POST request identifies the resource that will handle the enclosed entity. That resource might be a data-accepting process, a gateway to some other protocol, or a separate entity that accepts annotations. In contrast, the URI in a PUT request identifies the entity enclosed with the request -- the user agent knows what URI is intended and the server MUST NOT attempt to apply the request to some other resource. If the server desires that the request be applied to a different URI, it MUST send a 301 (Moved Permanently) response; the user agent MAY then make its own decision regarding whether or not to redirect the request.

更有可能是400个坏请求

[* * 6.5.1。400错误请求**][1]

400(坏请求)状态代码表示服务器不能或 将不会处理请求由于某些东西被认为是 客户端错误(例如,格式错误的请求语法,无效的请求 消息框架,或欺骗性请求路由)。

由于请求包含重复的值(已经存在的值),因此可以将其视为客户机错误。需要在下次尝试之前更改请求。 通过考虑这些事实,我们可以得出HTTP STATUS 400错误请求的结论。

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).