在RESTful应用程序中,我们如何区分“动作”和HTTP动词(GET、POST、PUT、DELETE)?

4
在RESTful应用程序中,我们如何区分“操作”和HTTP动词(GET、POST、PUT、DELETE)?
例如,我理解的是,对资源/products的GET请求应返回所有产品的列表。对/products的POST请求应创建一个新产品。那么,用户如何请求用于创建产品的原始表单?我的初步回答可能是对同一URI的GET请求,但如上所述,那应该返回所有产品的列表,而不是用于创建产品的空白表单。
在大多数我研究过的框架中,这个问题通过将“操作”部分作为URI的一部分来解决。例如,对/products/create的POST请求会创建一个新产品,而对/products/create的GET请求会提供用于创建产品的空白表单。要获取所有产品的列表,可以对/products或/products/get、/products/read等进行GET请求,具体取决于所使用的框架。这种方法解决了上述的歧义,但与我所读到的传统REST设计相冲突。

@RobertHarvey:因为“action”与HTTP动词重复。如果在URI中指定了一个操作,那么你只需要两个动词(即GETPOST)就足够了。 - FtDRbwLXw6
1
在一个纯粹的REST环境中,您将访问资源而不是操作。因此,要获取创建新产品的表单,您需要在/products/form URI上发出GET请求。然后,您可能会使用Javascript将表单转换为JSON请求,然后将其PUT到/products。正如您已经指出的那样,这种情况很少发生,可能部分原因是为了方便,部分原因是因为REST通常没有完全利用大多数Web资源。 - Robert Harvey
1
@RobertHarvey:如果我理解正确,你的意思是对于一个新产品的空白表单应该被视为独立的资源(仅支持GET方法),而不是产品资源的一种操作? - FtDRbwLXw6
在ASP.NET MVC中,“POST”动词由不同的控制器方法重载支持,该重载在提交时接受表单数据。 - Robert Harvey
@tereško 相关:http://stackoverflow.com/q/3900974 - Robert Harvey
显示剩余2条评论
2个回答

2

在我看来,最好的选择是将请求方法作为控制器动作的一部分。

假设您正在访问http://who.cares/product/42http://who.cares/product/42/specification。这个查询会转化为Product控制器。动作名称应通过组合请求方法和命令创建:

DELETE "http://who.cares/product/42"

    controller: "Product", 
    action:     "deleteProduct()" 


GET "http://who.cares/product/42/details"

    controller: "Product", 
    action:     "getDetails()"


POST "http://who.cares/product/42/review"

    controller: "Product", 
    action:     "postReview()"


GET "http://who.cares/products/ 

    controller: "Products", 
    action:     "getProducts()"


POST "http://who.cares/products/ 

    controller: "Products", 
    action:     "postProducts()"

这个选项会如何处理请求一个空白表单以输入新产品?URI 和操作会是什么? - FtDRbwLXw6
这更或多或少是ASP.NET MVC的工作方式。但由于控制器方法通常是URL的一部分,因此您仍然可以在URL中看到控制器方法名称,例如/products/create。GET和POST仅在表单请求和提交之间拆分。 - Robert Harvey
@tereško:但这并不能解释请求新产品表单和提交表单之间的区别。我知道提交表单应该是POST /product,但请求表单应该是什么呢?它不能是GET /product,因为那应该返回所有产品的集合。 - FtDRbwLXw6
@drrcknlsn,POST "http://who.cares/products/ 将转换为 postProducts() 方法。如果 URI 中没有设置回退命令,则回退命令与控制器名称相同。说实话,我仍然有点困惑 PUTPOST 之间的区别(我认为它们翻译为“保存”和“添加”)。您应该使用不同的控制器来处理项目列表:Products。另一个用于处理单个项目:Product - tereško
@tereško:我该使用哪个URI来检索创建产品时的空白表单?POST /products仅会_创建_新产品。但是,我应该如何_首先获取表单_,以便我可以填写并提交它? - FtDRbwLXw6
2
@drrcknlsn,我会选择GET "/products/new"。REST接口并不是针对HTML应用程序的。你这样做的目的是为第三方应用程序创建API。因此,返回HTML表单的请求不需要符合RESTful标准。 - tereško

1

这就像Rails所做的例子一样

REST request path    |  action name | Description
---------------------|-------------------|-------------
GET    /profile/new  | new               | Render a form for creating the profile
POST   /profile      | create            | Create a the profile from the received data
GET    /profile      | show              | Render a the profile
GET    /profile/edit | edit              | Render a form for editing the profile
PUT    /profile      | update            | Update the profile based on the received data
DELETE /profile      | destroy           | Destroy the profile

我没有看到任何冲突,想法是URL可读性强,您可以引入新的URI来显示相同资源的不同表示形式(例如profile/1/edit和profile/1)。 /profile/new - 空的个人资料地址(就像show方法中的profile/1、profile/2等) 但是如果您想要建议profile/1/edit是profile/1/资源的某种不同嵌套资源,那也可以,但我认为它只是profile/1/资源的另一种表示形式 =)
此外,在处理多个资源或一个资源时,使用复数和单数URI是一个好主意,例如:
/profile/1.html - gives you 1 resource
/profiles.html - gives you list of profiles

在ASP.NET MVC中,这应该是一个对/products/delete/123的POST操作。我从未见过有人实际上使用DELETE谓词。 - Robert Harvey
1
@drrcknlsn:问题的一部分是您需要一个确认页面来进行删除。因此,“delete”网址实际上是获取确认页面的GET请求。然后,在提交确认表单时,删除将在POST控制器方法中在幕后发生。HTML实际上只支持GET和POST动词。有关更多信息,请参见http://stephenwalther.com/archive/2009/01/21/asp-net-mvc-tip-46-ndash-donrsquot-use-delete-links-because.aspx。 - Robert Harvey
@RobertHarvey,我们的对话是关于REST,而不是HTML实际支持什么=)REST是关于HTTP的,几乎所有的Web框架都有模拟PUT、PATCH和其他HTTP动词的方法。 - Fivell
@RobertHarvey,您上面提供的链接只是关于ASP.NET如何实现REST,而不是关于REST本身的内容... - Fivell
@Fivell: 我提供链接的意义在于,你不应该对链接执行 DELETE 操作,因为 Google 爬取你的删除链接会对你的数据库造成严重破坏。这样的链接几乎总是 GET 请求。对于其他多余的信息,我很抱歉;我的经验是在 ASP.NET 上。 - Robert Harvey
显示剩余6条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接