我正在构建一个允许客户端存储对象的服务器.这些对象在客户端完全构造,完整的对象ID对于对象的整个生命周期是永久的.
我已经定义了API,以便客户端可以使用PUT创建或修改对象:
PUT /objects/{id} HTTP/1.1
...
{json representation of the object}
Run Code Online (Sandbox Code Playgroud)
{id}是对象ID,因此它是Request-URI的一部分.
现在,我也在考虑允许客户端使用POST创建对象:
POST /objects/ HTTP/1.1
...
{json representation of the object, including ID}
Run Code Online (Sandbox Code Playgroud)
由于POST意味着"附加"操作,我不知道如果对象已经存在该怎么做.我应该将请求视为修改请求还是应该返回一些错误代码(哪个)?
Wri*_*ken 951
我的感觉是409 Conflict最合适的,然而,当然在野外很少看到:
由于与资源的当前状态冲突,无法完成请求.此代码仅在预期用户可能能够解决冲突并重新提交请求的情况下才允许.响应主体应该包含足够的信息供用户识别冲突的来源.理想情况下,响应实体将包含足够的信息供用户或用户代理解决问题; 但是,这可能是不可能的,也不是必需的.
冲突最有可能发生在响应PUT请求时.例如,如果正在使用版本控制并且包含PUT的实体更改为与早期(第三方)请求所产生的资源冲突的资源,则服务器可能会使用409响应来指示它无法完成请求.在这种情况下,响应实体可能包含由响应Content-Type定义的格式的两个版本之间的差异列表.
Nul*_*ius 87
根据RFC 7231,可以使用303 See Other MAY 如果处理POST的结果等同于现有资源的表示.
Gar*_*eth 81
我个人使用WebDAV扩展422 Unprocessable Entity.
的
422 Unprocessable Entity状态代码装置的服务器理解的请求实体的内容类型(因此一个415 Unsupported Media Type状态码是不适当的),并且请求实体的语法是正确的(因此一个400 Bad Request状态码是不适当的),但无法处理所包含的指令.
wom*_*ire 47
在阅读了这篇文章以及其他几个长达数年的关于状态代码使用的讨论之后,我得出的主要结论是必须仔细阅读规范,重点关注所使用的术语、它们的定义、关系和周围的上下文。
相反,从不同的答案中可以看出,经常发生的情况是,规范的某些部分被脱离了上下文,并根据感觉和假设进行了孤立的解释。
这将是一个相当长的答案,其简短摘要是HTTP 409 是报告“添加新资源”操作失败的最合适的状态代码,以防具有相同标识符的资源已存在。以下是仅基于权威来源RFC 7231中所述内容的解释。
那么为什么409 Conflict在OP问题中描述的情况下最合适的状态代码是?
RFC 7231对409 Conflict状态码的描述如下:
409(冲突)状态代码表示由于与目标资源的当前状态发生冲突,请求无法完成。
这里的关键组件是目标资源及其状态。
目标资源
该资源由 RFC 7231 定义如下:
HTTP 请求的目标称为“资源”。HTTP 不限制资源的性质;它仅仅定义了一个可用于与资源交互的接口。每个资源都由统一资源标识符 (URI) 标识,如 [RFC7230] 的 2.7 节中所述。
因此,当使用 HTTP 接口时,我们总是通过对 URI 标识的资源应用 HTTP 方法来对其进行操作。
当我们打算添加新资源时,根据OP的示例,我们可以:
PUT与资源一起使用/objects/{id};POST与资源一起使用/objects。/objects/{id}出于兴趣,因为使用方法时不能发生冲突PUT:
PUT 方法请求创建目标资源的状态或用请求消息有效负载中包含的表示定义的状态替换目标资源的状态。
如果具有相同标识符的资源已经存在,则会被替换为PUT。
因此,我们将重点关注/objects资源和POST。
RFC 7231 说道POST:
POST 方法请求目标资源根据资源自身的特定语义处理请求中包含的表示。例如,POST 用于以下功能(除其他外): ... 3) 创建尚未被源服务器识别的新资源;4) 将数据附加到资源的现有表示。
与OP理解方法相反POST:
由于 POST 意味着“追加”操作......
将数据附加到资源的现有表示只是可能的“功能”之一POST。此外,OP 在提供的示例中实际所做的并不是直接将数据附加到/objects表示,而是创建一个新的独立资源/objects/{id},然后该资源成为表示的一部分/objects。但这并不重要。
重要的是资源表示的概念,它让我们……
资源状态
RFC 7231 解释:
考虑到资源可以是任何东西,并且 HTTP 提供的统一接口类似于一个窗口,通过该窗口,人们只能通过与另一端的某个独立参与者通信消息来观察和操作此类事物,因此抽象是需要在我们的通信中表示(“取代”)该事物的当前或期望状态。该抽象称为表示 [REST]。
就 HTTP 而言,“表示”是旨在以可以通过协议轻松传达的格式反映给定资源的过去、当前或所需状态的信息,并且由一组表示组成元数据和潜在无限的表示数据流。
这还不是全部,规范继续描述表示部分 - 元数据和数据,但我们可以总结一下,由元数据(标头)和数据(有效负载)组成的资源表示反映了资源的状态。
现在我们已经有了理解状态代码用法所需的两个部分409 Conflict。
409 冲突
让我们重申一下:
409(冲突)状态码表示由于与目标资源的当前状态冲突而无法完成请求。
那么如何搭配呢?
POST= /objects> 我们的目标资源是/objects。/objects资源,但该示例看起来像是一个常见场景,其中/objects是一个资源集合,包含所有单独的“对象”资源。也就是说,资源的状态包括关于所有现有资源的知识。/objects/object/{id}/objects资源处理POST请求时,它必须 a)/object/{id}根据请求负载中传递的数据创建新资源;b) 通过添加有关新创建资源的数据来修改其自身状态。/object/{id}当要创建的资源具有重复的标识符时,即已存在具有相同 URI 的资源时,该/objects资源将无法处理POST请求,因为其状态已包含重复的/object/{id}URI。这正是状态码描述中提到的与目标资源当前状态的冲突409 Conflict。
p0l*_*ear 26
可能在游戏后期,但我在尝试制作REST API时偶然发现了这个语义问题.
为了扩展Wrikken的答案,我认为您可以使用409 Conflict或403 Forbidden根据具体情况 - 简而言之,当用户无法解决冲突并完成请求时(例如他们无法发送请求)时,请使用403错误DELETE请求显式删除资源),或者如果可能的话可以使用409.
10.4.4 403禁止
服务器理解请求,但拒绝履行请求.授权无效,请求不应重复.如果请求方法不是HEAD并且服务器希望公开为什么请求没有得到满足,那么它应该描述实体中拒绝的原因.如果服务器不希望将此信息提供给客户端,则可以使用状态代码404(未找到).
如今,有人说"403"并且出现了权限或身份验证问题,但规范说它基本上是服务器告诉客户端它不会这样做,不要再问它,这就是为什么客户端不应该"T.
至于PUTvs. POST... POST应该用于在用户无法或不应该为资源创建标识符时创建资源的新实例.PUT在知道资源的标识时使用.
9.6 PUT
...
POST和PUT请求之间的根本区别体现在Request-URI的不同含义上.POST请求中的URI标识将处理所包含实体的资源.该资源可能是数据接受过程,某些其他协议的网关或接受注释的单独实体.相反,PUT请求中的URI标识请求附带的实体 - 用户代理知道URI的用途,并且服务器不得尝试将请求应用于其他资源.如果服务器希望将请求应用于不同的URI,
必须发送301(永久移动)响应; 然后,用户代理可以自己决定是否重定向请求.
Sła*_*art 19
这全都与上下文有关,还有谁负责在请求中重复(服务器或客户端或两者)
如果服务器仅指向重复项,请查看4xx:
要隐式处理重复项,请查看2XX:
如果服务器期望返回某些内容,请查看3XX:
当服务器能够指向现有资源时,则意味着重定向。
如果上述还不够,在响应正文中准备一些错误消息始终是一个好习惯。
ala*_*jds 14
"302 Found"听起来合情合理.并且RFC 2616说它可以回答除GET和HEAD之外的其他请求(这肯定包括POST)
但是它仍然让访问者通过这个URL来获取RFC的"Found"资源.为了使它直接进入真正的"找到"URL,应该使用"303 See Other",这是有道理的,但强制另一个调用GET以下的URL.好的方面,这个GET是可缓存的.
我想我会用"303见其他".我不知道我是否可以回复身体中发现的"东西",但我想这样做是为了将一次往返保存到服务器上.
更新:重新阅读RFC之后,我仍然认为不存在的 "4XX + 303 Found"代码应该是正确的.但是,"409 Conflict"是现有的最佳答案代码(由@ Wrikken指出),可能包括指向现有资源的Location头.
Alf*_*nda 11
我认为你不应该这样做.
如您所知,POST是修改集合的,它用于创建新项目.所以,如果你发送id(我认为这不是一个好主意),你应该修改集合,即修改项目,但这是令人困惑的.
用它来添加一个没有id的项目.这是最好的做法.
如果要捕获UNIQUE约束(而不是id),则可以响应409,就像在PUT请求中一样.但不是身份证.
在您的情况下,您可以使用 409 Conflict
如果你想HTTPs从下面的列表中检查另一个状态代码
1×× 信息
100 Continue
101 Switching Protocols
102 Processing
Run Code Online (Sandbox Code Playgroud)
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
Run Code Online (Sandbox Code Playgroud)
3×× 重定向
300 Multiple Choices
301 Moved Permanently
302 Found
303 See Other
304 Not Modified
305 Use Proxy
307 Temporary Redirect
308 Permanent Redirect
Run Code Online (Sandbox Code Playgroud)
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
Run Code Online (Sandbox Code Playgroud)
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
Run Code Online (Sandbox Code Playgroud)
我认为对于REST,你只需要对该特定系统的行为做出决定,在这种情况下,我认为"正确"的答案将是这里给出的几个答案之一.如果您希望请求停止并且行为就好像客户端在继续之前犯了一个需要修复的错误,那么使用409.如果冲突真的不那么重要并且想要保持请求继续,那么通过重定向来响应客户端到找到的实体.我认为正确的REST API应该在POST之后重定向(或者至少提供位置头)到该资源的GET端点,因此这种行为将提供一致的体验.
编辑:值得注意的是,您应该考虑PUT,因为您提供了ID.然后行为很简单:"我不在乎现在有什么,把这个东西放在那里." 意思是,如果没有任何东西,它就会被创造出来; 如果有东西它会被替换.我认为当服务器管理该ID时,POST更合适.分离这两个概念基本上告诉你如何处理它(即PUT是幂等的,所以只要有效载荷有效,它总是有效,POST总是创建,所以如果有ID冲突,那么409会描述这个冲突) .
我会使用422 Unprocessable Entity,当请求无效但问题不在语法或身份验证中时使用.
作为反对其他答案的论据,使用任何非4xx错误代码意味着它不是客户端错误,显然是.使用非4xx错误代码来表示客户端错误根本没有任何意义.
这似乎409 Conflict是这里最常见的答案,但是,根据规范,这意味着资源已经存在,并且您应用于它的新数据与其当前状态不兼容.如果您要发送POST请求,例如,已经使用的用户名,则它实际上并不与目标资源冲突,因为目标资源尚未发布到.当存储的资源版本与请求的资源版本之间存在冲突时,这是一个专门用于版本控制的错误.它对于此目的非常有用,例如,当客户端缓存旧版本的资源并根据不再有条件有效的不正确版本发送请求时."在这种情况下,响应表示可能包含有助于根据修订历史合并差异的信息." 使用该用户名创建另一个用户的请求是无法处理的,与版本控制无关.
对于记录,422也是当您尝试使用已在使用的名称创建存储库时GitHub使用的状态代码.
为什么不接受202?这是一个OK请求(200s),本身没有客户端错误(400s).
来自10个状态码定义:
"202已接受.该请求已被接受处理,但处理尚未完成."
...因为它不需要完成,因为它已经存在.客户不知道它已经存在,他们没有做错任何事.
我倾向于投掷一个202,并返回类似的内容到GET /{resource}/{id}会返回的内容.
| 归档时间: |
|
| 查看次数: |
313222 次 |
| 最近记录: |