了解REST:动词,错误代码和身份验证


602

我正在寻找一种在基于PHP的Web应用程序,数据库和CMS中将API围绕默认功能包装的方法。

我环顾四周,发现了几个“骨架”框架。除了我的问题的答案之外,还有Tonic,我喜欢它是REST框架,因为它非常轻巧。

我最喜欢REST的原因在于它的简单性,并希望基于它创建一个API架构。我正在努力了解基本原理,但尚未完全理解它。因此,有很多问题。

1.我理解正确吗?

说我有一个资源“用户”。我可以像这样设置许多URI:

/api/users     when called with GET, lists users
/api/users     when called with POST, creates user record
/api/users/1   when called with GET, shows user record
               when called with PUT, updates user record
               when called with DELETE, deletes user record

到目前为止,这是RESTful架构的正确表示吗?

2.我需要更多动词

从理论上讲,创建,更新和删除可能就足够了,但实际上,我将需要更多的动词。我知道这些事情,可以嵌入到更新请求,但他们是可以有具体的返回代码的具体行动,我不希望他们全部扔进一个动作。

在用户示例中想到的一些是:

activate_login
deactivate_login
change_password
add_credit

我如何表达诸如RESTful URL架构中的动作?

我的直觉是对URL之类的GET调用

/api/users/1/activate_login 

并期待返回状态码。

但是,这与使用HTTP动词的想法不同。你怎么看?

3.如何返回错误消息和代码

REST之美的很大一部分源于其对标准HTTP方法的使用。发生错误时,我发出带有3xx,4xx或5xx错误状态代码的标头。有关错误的详细说明,我可以使用主体(对吗?)。到目前为止,一切都很好。但是,传输专有错误代码的方式又是什么呢?该错误代码将在描述错误原因(例如“连接数据库失败”或“数据库登录错误”)中进行更详细的说明。如果将其与消息一起放入正文中,则必须在以后对其进行解析。是否有用于此类事物的标准标头?

4.如何进行身份验证

  • 遵循REST原理的基于API密钥的身份验证会是什么样?
  • 除了对REST原则公然违反之外,在验证REST客户端时是否有使用会话的强项?:)(在这里开个玩笑,基于会话的身份验证可以在我现有的基础架构中很好地发挥作用。)

13
@Daniel,感谢您的编辑。“我更多的动词”是故意的双关语,但我将其保留,现在更容易阅读了。:)
Pekka 2010年

1
顺便说一句,关于错误描述。最后,我将错误描述放入响应的标头中。只需添加名为“错误描述”的标头即可。
Andrii Muzychuk 2015年

这看起来更像是应用程序安全性问题。应用程序安全性与REST无关。
纳扎·梅尔扎

@NazarMerza 1.,2。和3.应用程序安全性问题如何?
佩卡

Answers:


620

我几天后才注意到这个问题,但我觉得我可以补充一些见识。我希望这可以对您的RESTful事业有所帮助。


第一点:我理解正确吗?

你说的没错。这是RESTful架构的正确表示。您可能会发现Wikipedia中的以下矩阵对于定义名词和动词非常有帮助:


处理Collection URI时,例如:http://example.com/resources/

  • GET:列出集合的成员,并带有其成员URI以便进一步导航。例如,列出所有待售汽车。

  • PUT:定义为“将整个集合替换为另一个集合”。

  • POST:在集合中创建一个新条目,其中ID由集合自动分配。创建的ID通常包含在此操作返回的数据中。

  • DELETE:定义为“删除整个集合”的含义。


处理成员 URI时,例如:http://example.com/resources/7HOU57Y

  • GET:检索以适当的MIME类型表示的集合中所寻址成员的表示形式。

  • PUT:更新集合的寻址成员或使用指定的ID创建它。

  • POST:将被寻址成员本身视为一个集合,并为其创建新的下属。

  • DELETE:删除集合中寻址的成员。


第二点:我需要更多动词

通常,当您认为您需要更多的动词时,实际上可能意味着您的资源需要重新标识。请记住,在REST中,您总是在作用于资源或资源的集合。您选择的资源对于您的API定义非常重要。

激活/停用登录:如果要创建新会话,则可能需要将“会话”视为资源。要创建新会话,请使用POST到http://example.com/sessions/正文中的凭据。要使其过期,请使用PUT或DELETE(可能取决于您是否要保留会话历史记录)到http://example.com/sessions/SESSION_ID

更改密码:这次资源是“用户”。您需要将PUT http://example.com/users/USER_ID与正文中的新旧密码一起使用。您正在使用“用户”资源,更改密码只是一个更新请求。它与关系数据库中的UPDATE语句非常相似。

我的直觉是对URL之类的GET调用 /api/users/1/activate_login

这违反了一个非常核心的REST原则:HTTP动词的正确用法。任何GET请求都不应留下任何副作用。

例如,GET请求永远不要在数据库上创建会话,返回具有新会话ID的cookie或在服务器上保留任何残差。GET动词类似于数据库引擎中的SELECT语句。请记住,使用相同的参数请求时,使用GET动词对任何请求的响应都应该是可缓存的,就像您请求静态网页一样。


第3点:如何返回错误消息和代码

将4xx或5xx HTTP状态代码视为错误类别。您可以在正文中详细说明错误。

无法连接到数据库: / 错误的数据库登录:对于这些类型的错误,通常应使用500错误。这是服务器端错误。客户没有做错任何事。通常将500个错误视为“可重试”。也就是说,客户端可以重试相同的确切请求,并期望一旦服务器的问题解决,请求就会成功。在正文中指定详细信息,以便客户可以向我们的工作人员提供一些背景信息。

错误的另一类是4xx系列,通常表示客户端做错了什么。尤其是,此类错误通常会向客户端指示不需要按原样重试请求,因为它将继续永久失败。也就是说,客户端需要在重试此请求之前进行一些更改。例如,“找不到资源”(HTTP 404)或“格式错误的请求”(HTTP 400)错误将属于此类别。


要点4:如何进行身份验证

正如第1点所指出的,您可能需要考虑创建会话,而不是对用户进行身份验证。您将获得一个新的“会话ID”以及相应的HTTP状态代码(200:已授予访问权限或403:已拒绝访问)。

然后,您将问您的RESTful服务器:“您能为我获取此会话ID的资源吗?”。

没有身份验证模式-REST是无状态的:创建会话,要求服务器使用此会话ID作为参数为您提供资源,并在注销时删除或终止该会话。


6
很好,但是您使用的PUT更改密码可能不正确;PUT需要整个资源,因此您必须发送所有用户属性才能符合HTTP(因此符合HATEOAS REST)。相反,要简单地更改密码,应使用PATCHPOST
劳伦斯·多尔

1
我认为,如果您对以下内容进行更多的扩展,则该帖子将是完美的:“帖子:将被寻址的成员本身视为一个集合,并为其创建新的从属”。手段。-我发现Google搜寻是什么意思-这是您原本不错的答案的例外。
Martin Konecny 2014年

6
我不同意最后一句话。您正在解释REST如何是无状态的。登录以创建会话,然后在完成一些工作后注销以结束会话是有状态API的最佳示例。
布兰登

1
“这违反了一个非常核心的REST原则:正确地使用HTTP动词。任何GET请求都永远不会产生任何副作用。” -如果您要维护资源的点击数怎么办?
bobbyalex


79

简而言之,您正在完全落后。

您不应该从应该使用的URL处获取信息。一旦您确定了系统所需的资源以及如何表示这些资源以及资源与应用程序状态之间的交互,这些URL将有效地“免费”出现。

引用罗伊·菲尔丁(Roy Fielding)

REST API应该花费几乎所有的描述性精力来定义用于表示资源和驱动应用程序状态的媒体类型,或者为现有标准媒体类型定义扩展的关系名称和/或启用超文本的标记。花费所有精力描述应该在媒体类型的处理规则范围内(并且在大多数情况下已由现有媒体类型定义)完全定义要在感兴趣的URI上使用的方法。[此处的失败表示带外信息正在驱动交互,而不是超文本。

人们总是以URI开头,并认为这是解决方案,然后他们往往会错过REST体系结构中的一个关键概念,特别是,如上文所述,“此处的失败表示带外信息正在推动交互而非超文本。 ”

老实说,许多人看到了很多URI以及一些GET,PUT和POST,并认为REST很容易。REST并不容易。通过HTTP进行RPC很容易,通过HTTP有效负载来回移动数据块很容易。REST不仅如此。REST与协议无关。HTTP只是非常流行,并且适用于REST系统。

REST存在于媒体类型,它们的定义以及应用程序如何通过超文本(有效地链接)来驱动那些资源可用的操作中。

关于REST系统中的媒体类型有不同的看法。一些支持特定于应用程序的有效负载,而另一些支持将现有媒体类型提升为适合该应用程序的角色。例如,一方面,您已经设计了适合您的应用程序的特定XML模式,而不是通过微格式和其他机制使用诸如XHTML的表示形式。

我认为,这两种方法在XHTML都可以很好地与人为驱动和机器驱动的Web重叠的情况下都能很好地发挥作用,而我认为前者更具体的数据类型更好地促进了机器对机器的交互。我发现商品格式的提升可能会使内容协商变得困难。“ application / xml + yourresource”作为媒体类型比“ application / xhtml + xml”更具体,因为后者可以应用于许多有效负载,这些负载可能是机器客户端真正感兴趣的东西,也可能不是无需内省即可确定。

但是,XHTML在Web上的浏览器和呈现非常重要的人类网络中(显然)工作得很好。

您的应用程序将指导您进行此类决策。

设计REST系统的过程的一部分是发现系统中的一流资源以及派生的支持资源,以支持对主要资源的操作。一旦发现资源,这些资源的表示形式以及由于下一个挑战而通过表示形式中的超文本显示资源流的状态图。

回想一下,在超文本系统中,资源的每种表示形式都将实际的资源表示形式与资源可用的状态转换结合在一起。将每个资源视为图中的一个节点,链接是使该节点保持其他状态的线。这些链接不仅通知客户端可以做什么,而且还通知客户端要完成它们所需的操作(因为良好的链接结合了URI和所需的媒体类型)。

例如,您可能有:

<link href="http://example.com/users" rel="users" type="application/xml+usercollection"/>
<link href="http://example.com/users?search" rel="search" type="application/xml+usersearchcriteria"/>

您的文档将讨论名为“ users”的rel字段,以及“ application / xml + youruser”的媒体类型。

这些链接似乎是多余的,它们几乎都在使用相同的URI。但事实并非如此。

这是因为对于“用户”关系,该链接所讨论的是用户集合,您可以使用统一的界面来处理用户集合(GET检索所有用户,DELETE删除所有用户,等等)。

如果您发布到该URL,则需要传递一个“ application / xml + usercollection”文档,该文档可能仅包含一个用户实例,因此您可以添加该用户,也可以不添加该用户,例如一旦。也许您的文档会建议您只传递一个用户类型,而不是集合。

您可以查看应用程序执行搜索所需要的内容,如“搜索”链接及其媒体类型所定义。搜索媒体类型的文档将告诉您它的行为方式以及预期结果。

不过,这里的要点是URI本身基本上并不重要。该应用程序由URI控制,而不由客户端控制。除了一些“入口点”,您的客户还应依靠应用程序提供的URI进行工作。

客户需要知道如何操纵和解释媒体类型,但是并不需要关心它的去向。

在客户看来,以下两个链接在语义上是相同的:

<link href="http://example.com/users?search" rel="search" type="application/xml+usersearchcriteria"/>
<link href="http://example.com/AW163FH87SGV" rel="search" type="application/xml+usersearchcriteria"/>

因此,请专注于您的资源。专注于他们在应用程序中的状态转换以及如何最好地实现。


1
谢谢威尔的深刻回答。采取了几点。我意识到从“ URL的外观”进行规划是相反的,并且我也在资源方面进行规划。使用URL可以使我更容易理解这个概念。这可能是我的要求可以用未100%随访REST原则,你在这里把它定义系统来满足。我将为每种资源类型绘制一份完整的需求列表,我想我以后可以决定。干杯。
Pekka 2010年

30

关于1:到目前为止看起来还不错。切记在“ Location:”标头中返回新创建的用户的URI,作为对POST响应的一部分,并返回“ 201 Created”状态代码。

关于2:通过GET激活是一个坏主意,并且在URI中包含动词是一种设计气味。您可能要考虑在GET上返回表单。在Web应用程序中,这将是带有提交按钮的HTML表单。在API用例中,您可能需要向PUT返回包含URI的表示形式以激活帐户。当然,您也可以在对/ users的POST响应中包含此URI。使用PUT将确保您的请求是幂等的,即,如果客户端不确定成功是否可以安全地再次发送。通常,考虑一下可以将动词转化为哪些资源(一种“动词名词化”)。问问自己,您的特定动作最接近于哪种方法。例如change_password-> PUT; 停用->可能是DELETE; add_credit->可能是POST或PUT。

关于3.不要发明新的状态码,除非您认为它们是如此通用,所以值得在全球范围内进行标准化。尝试使用可用的最合适的状态代码(有关详细信息,请参阅RFC 2616)。在响应正文中包括其他信息。如果您真的确定要发明一个新的状态码,请再考虑一遍。如果仍然相信,请确保至少选择正确的类别(1xx->确定,2xx->信息性,3xx->重定向; 4xx->客户端错误,5xx->服务器错误)。我是否提到发明新的状态代码是一个坏主意?

4.如果可能,请使用HTTP内置的身份验证框架。了解Google在GData中进行身份验证的方式。通常,请勿将API密钥放在您的URI中。尝试避免使用会话来增强可伸缩性并支持缓存-如果由于之前发生的事情而导致对请求的响应有所不同,则通常会将自己绑定到特定的服务器流程实例。最好将会话状态转换为客户端状态(例如,使其成为后续请求的一部分)或通过将其转换为(服务器)资源状态(即为其提供自己的URI)来使其显式。


您能讨论为什么不将API密钥放在URL中吗?是否因为它们在代理日志中可见?如果密钥是基于时间的临时密钥,该怎么办?如果使用HTTPS怎么办?
MikeSchinkel 2010年

4
除了违反精神(URI应该标识事物)之外,主要的后果是它破坏了缓存。
Stefan Tilkov

22

1.恕我直言,您对如何设计资源有正确的想法。我不会改变任何事情。

2.不要尝试用更多的动词来扩展HTTP,而是考虑可以根据基本的HTTP方法和资源将建议的动词简化为什么。例如,activate_login您可以设置类似以下/api/users/1/login/active内容的资源来代替动词::这是一个简单的布尔值。要激活登录名,只需PUT在其中显示“ true”或1或任何其他名称的文档即可。要停用PUT此文档,该文档为空或显示0或false。

同样,要更改或设置密码,只需对PUT进行操作/api/users/1/password

每当您需要添加某些内容(例如信用)时,请以POSTs 为单位。例如,您可以对包含包含要添加的学分数量的主体POST的资源执行a操作/api/users/1/creditsPUT可以使用同一资源上的A 来覆盖值而不是添加。POST体内具有负数的A 将减去,依此类推。

3.我强烈建议不要扩展基本的HTTP状态代码。如果找不到与您的情况完全匹配的解决方案,请选择最接近的一种,并将错误详细信息放入响应正文中。另外,请记住,HTTP标头是可扩展的。您的应用程序可以定义您喜欢的所有自定义标头。例如,我处理过的一个应用程序可能404 Not Found在多种情况下返回a 。我们没有添加客户端解析原因的原因,而是添加了一个新的标头X-Status-Extended,其中包含我们专有的状态代码扩展。因此,您可能会看到如下响应:

HTTP/1.1 404 Not Found    
X-Status-Extended: 404.3 More Specific Error Here

这样,像Web浏览器这样的HTTP客户端仍然会知道如何处理常规404代码,而更复杂的HTTP客户端可以选择查看X-Status-Extended标头以获取更多特定信息。

4.对于身份验证,建议您尽可能使用HTTP身份验证。但是,恕我直言,使用基于cookie的身份验证对您来说没有任何问题。


4
使用“扩展的”资源对较大资源的较小部分执行操作的巧妙想法。
摇晃

1
Cookie在HTTP / REST中有效,但服务器不应将Cookie存储为状态(因此不能存储为会话)。cookie可以存储类似HMAC的值,但是可以在不查找其他状态的情况下将其分解。
Bruce Alderson

14

REST基础

REST具有统一的接口约束,该约束指出REST客户端必须依赖于标准,而不是实际REST服务的应用程序特定细节,因此REST客户端不会受到较小的更改,并且可以重用。

因此,REST客户端与REST服务之间存在合同。如果您使用HTTP作为基础协议,那么以下标准是合同的一部分:

  • HTTP 1.1
    • 方法定义
    • 状态码定义
    • 缓存控制标头
    • 接受和内容类型标题
    • auth头
  • IRI(utf8 URI
  • 身体(一个)
    • 注册的应用程序特定的MIME类型,例如maze + xml
    • 供应商特定的MIME类型,例如vnd.github + json
    • 通用MIME类型,带有
  • 超连结
    • 应该包含什么(选择一个)
      • 发送链接头
      • 发送超媒体响应,例如html,atom + xml,hal + json,ld + json&hydra等...
    • 语义学
      • 使用IANA链接关系以及可能的自定义链接关系
      • 使用特定于应用程序的RDF vocab

REST具有无状态约束,该约束声明REST服务与客户端之间的通信必须是无状态的。这意味着REST服务无法维护客户端状态,因此您不能拥有服务器端会话存储。您必须对每个请求进行身份验证。因此,例如HTTP基本身份验证(HTTP标准的一部分)是可以的,因为它随每个请求发送用户名和密码。

回答你的问题

  1. 是的,可以。

    只需提及,客户端并不关心IRI结构,而是关心语义,因为它们遵循具有链接关系或链接数据(RDF)属性的链接。

    关于IRI唯一重要的事情是,单个IRI必须仅标识单个资源。允许单个资源(如用户)具有许多不同的IRI。

    为什么我们使用类似IRI这样的漂亮IRI很简单/users/123/password。当您仅通过阅读IRI来理解IRI时,在服务器上编写路由逻辑就容易得多。

  2. 您有更多的动词,例如PUT,PATCH,OPTIONS甚至更多,但是您并不需要更多...除了添加新的动词,您还必须学习如何添加新的资源。

    activate_login -> PUT /login/active true deactivate_login -> PUT /login/active false change_password -> PUT /user/xy/password "newpass" add_credit -> POST /credit/raise {details: {}}

    (由于无状态限制,从REST角度看,登录没有意义。)

  3. 您的用户不关心问题存在的原因。他们只想知道是成功还是出错,并且可能知道他们理解的错误消息,例如:“抱歉,我们无法保存您的帖子。”,等等。

    HTTP状态标头是您的标准标头。我认为其他一切都应该在体内。单个标头不足以描述例如详细的多语言错误消息。

  4. 无状态约束(以及缓存和分层系统约束)可确保服务扩展良好。当您可以在客户端上执行相同的操作时,您肯定不会在服务器上维护数百万个会话。

    如果用户使用主客户端授予访问令牌,则第三方客户端将获得访问令牌。之后,第三方客户端将随每个请求一起发送访问令牌。有更复杂的解决方案,例如您可以签署每个请求等。有关更多详细信息,请参阅OAuth手册。

相关文献


11

对于您说的示例,我将使用以下代码:

activate_login

POST /users/1/activation

deactivate_login

DELETE /users/1/activation

更改密码

PUT /passwords (这假设用户已通过身份验证)

add_credit

POST /credits (这假设用户已通过身份验证)

对于错误,您将以收到请求的格式在正文中返回错误,因此,如果收到:

DELETE /users/1.xml

您将以XML格式发送回响应,对于JSON等也是如此。

对于身份验证,您应该使用http身份验证。


1
我不会将其create用作URI的一部分(请记住URI应该是名词,而HTTP方法应该是对这些名词进行操作的动词。)相反,我会有类似/users/1/active这样的资源,它可以是一个简单的布尔值,并且可以通过将1或0放入该资源来设置。
Friedo 2010年

您是对的,我取出了/ create。它仅应发布到单例资源。
jonnii 2010年

3
activation除非您将通过的名称显式操作和管理资源,否则我也不会在URI上使用/users/1/activation。GET可以做什么?PUT会做什么?在我看来,您确实在泛化URI。另外,对于内容类型协商,通常最好也不要将它放在URI中,而是插入标头中,例如Accept
Cheeso

6
  1. 当您不知道新资源URI的外观(创建新用户,应用程序将为新用户分配其ID)时,请使用post,使用PUT来更新或创建您知道如何表示资源的资源(示例:PUT /myfiles/thisismynewfile.txt)
  2. 在消息正文中返回错误描述
  3. 您可以使用HTTP身份验证(如果足够的话),Web服务应该处于状态状态

5

我建议(作为第一步)PUT仅应用于更新现有实体。POST应该用于创建新的。即

/api/users     when called with PUT, creates user record

我觉得不对。但是,第一部分的其余部分(动词用法)看起来很合逻辑。


可能有人认为这并不是他的问题的真正答案
lubos hasko 2010年

6
在创建新实体时,我对PUT与POST的比较是在调用方控制资源名称时使用PUT,因此您可以将PUT精确定位到资源,而在被调用方控制新资源名称时可以进行POST(例如此处的示例)。
SteveD 2010年

5

详细,但是从HTTP 1.1方法规范中复制的,网址http://www.w3.org/Protocols/rfc2616/rfc2616-sec9.html

9.3获取

GET方法意味着检索由Request-URI标识的任何信息(以实体形式)。如果Request-URI指的是数据产生过程,则应将产生的数据作为响应中的实体而不是过程的源文本作为实体返回,除非该文本恰好是过程的输出。

如果请求消息包含If-Modified-Since,If-Unmodified-Since,If-Match,If-None-Match或If-Range头字段,则GET方法的语义将变为“条件GET”。条件GET方法仅在条件标头字段描述的情况下才请求转移实体。有条件的GET方法旨在通过允许刷新缓存的实体而无需多个请求或传输客户端已经拥有的数据来减少不必要的网络使用。

如果请求消息包含Range标头字段,则GET方法的语义将更改为“部分GET”。如第14.35节所述,部分GET请求仅转移实体的一部分。部分GET方法旨在通过允许部分取回的实体完成而无需传输客户端已经拥有的数据来减少不必要的网络使用。

且仅当满足GET请求的响应符合第13节中描述的HTTP缓存要求时,该响应才可以缓存。

有关用于表格的安全性注意事项,请参见15.1.3节。

9.5开机自检

POST方法用于请求源服务器接受请求中包含的实体作为请求行中Request-URI标识的资源的新下属。POST旨在允许采用统一的方法来覆盖以下功能:

  - Annotation of existing resources;
  - Posting a message to a bulletin board, newsgroup, mailing list,
    or similar group of articles;
  - Providing a block of data, such as the result of submitting a
    form, to a data-handling process;
  - Extending a database through an append operation.

POST方法执行的实际功能由服务器确定,通常取决于Request-URI。发布的实体从属于该URI,其方式类似于文件从属于包含该实体的目录,新闻从属于其发布到的新闻组,或者记录从属于数据库。

POST方法执行的操作可能不会导致可以由URI标识的资源。在这种情况下,适当的响应状态是200(确定)或204(无内容),这取决于响应是否包括描述结果的实体。

如果在原始服务器上已经创建了资源,则响应应该为201(已创建),并包含一个描述请求状态并引用新资源的实体以及一个Location头(参见14.30节)。

除非响应包含适当的Cache-Control或Expires标头字段,否则对此方法的响应不可缓存。但是,303(请参阅其他)响应可用于指导用户代理检索可缓存的资源。

POST请求必须遵守第8.2节中规定的消息传输要求。

出于安全考虑,请参阅第15.1.3节。

9.6放置

PUT方法请求将封闭的实体存储在提供的Request-URI下。如果Request-URI引用了已经存在的资源,则应将封闭的实体视为原始服务器上的资源的修改版本。如果Request-URI没有指向现有资源,并且请求用户代理能够将该URI定义为新资源,则原始服务器可以使用该URI创建资源。如果创建了新资源,则原始服务器务必通过201(已创建)响应通知用户代理。如果修改了现有资源,则应发送200(确定)或204(无内容)响应代码以指示请求已成功完成。如果无法使用Request-URI创建或修改资源,应该给出反映问题性质的适当的错误响应。实体的接收者不得忽略其无法理解或实现的任何Content-*(例如Content-Range)标头,并且在这种情况下必须返回501(未实现)响应。

如果请求通过缓存,并且Request-URI标识一个或多个当前缓存的实体,则应将这些条目视为过期。此方法的响应不可缓存。

POST和PUT请求之间的根本区别体现在Request-URI的不同含义上。POST请求中的URI标识将处理封闭实体的资源。该资源可能是数据接受过程,通往某些其他协议的网关或接受注释的单独实体。相比之下,PUT请求中的URI标识请求中包含的实体-用户代理知道要使用的URI,并且服务器绝不能尝试将请求应用于其他资源。如果服务器希望将请求应用于其他URI,

它必须发送301(永久移动)响应;然后,用户代理可以自行决定是否重定向请求。

单个资源可以由许多不同的URI标识。例如,文章可能具有用于标识“当前版本”的URI,该URI与标识每个特定版本的URI分开。在这种情况下,对通用URI的PUT请求可能会导致原始服务器定义其他几个URI。

HTTP / 1.1并未定义PUT方法如何影响原始服务器的状态。

PUT请求必须遵守第8.2节中规定的消息传输要求。

除非为特定的实体头另有规定,否则PUT请求中的实体头应该应用于由PUT创建或修改的资源。

9.7删除

DELETE方法请求原始服务器删除由Request-URI标识的资源。在原始服务器上,人为干预(或其他方式)可能会覆盖此方法。即使从原始服务器返回的状态代码指示该操作已成功完成,也不能保证客户机已执行了该操作。但是,服务器不应指示成功,除非在给出响应时服务器打算删除资源或将其移动到无法访问的位置。

如果响应包含描述状态的实体,则成功响应应该为200(确定);如果尚未执行该操作,则为202(接受);如果已经执行该动作但响应不包括该响应,则返回204(无内容)。一个实体。

如果请求通过缓存,并且Request-URI标识一个或多个当前缓存的实体,则应将这些条目视为过期。此方法的响应不可缓存。


2

关于REST返回码:混合使用HTTP协议代码和REST结果是错误的

但是,我看到许多实现混在一起,许多开发人员可能不同意我的看法。

HTTP返回码与HTTP Request自身相关。REST调用是使用超文本传输​​协议请求完成的,它的工作级别比调用的REST方法本身低。REST是一种概念/方法,其输出是业务/逻辑结果,而HTTP结果代码是一种传输

例如,在调用/ users /时返回“ 404 Not found”很容易混淆,因为这可能意味着:

  • URI错误(HTTP)
  • 找不到用户(REST)

“ 403禁止/拒绝访问”可能表示:

  • 需要特殊许可。浏览器可以通过询问用户/密码来处理它。(HTTP)
  • 服务器上配置的访问权限错误。(HTTP)
  • 您需要通过身份验证(REST)

并且该列表可能会继续显示“ 500服务器错误”(Apache / Nginx HTTP抛出错误或REST中的业务约束错误)或其他HTTP错误等。

从代码中,很难理解什么是失败原因,HTTP(传输)失败或REST(逻辑)失败。

如果HTTP请求在物理上成功执行,则无论是否找到记录,它都应始终返回200代码。因为找到了 URI资源并由http服务器处理。是的,它可能会返回一个空集。是否可能会收到一个空页面,显示http结果为200,对吗?

取而代之的是,您可以返回200个HTTP代码以及一个带有空数组/对象的JSON,或者使用bool结果/成功标志来告知已执行的操作状态。

此外,某些互联网提供商可能会拦截您的请求并返回404 http代码。这并不意味着未找到您的数据,但是在传输级别是有问题的。

维基

2004年7月,英国电信提供商BT Group部署了Cleanfeed内容阻止系统,该程序将对Internet Watch Foundation认定为潜在违法的任何内容请求返回404错误。在相同的情况下,其他ISP返回HTTP 403“禁止”错误。泰国和突尼斯也有报道采用伪造的404错误作为掩盖审查的手段。在突尼斯,2011年革命之前审查制度很严厉,人们开始意识到伪造的404错误的性质,并创建了一个假想的人物,名为“ Ammar 404”,代表“无形的审查者”。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.