使用Zend Framework构建RESTful API时,上传文件应该使用PUT还是POST?

66
我正在使用Zend Framework通过Zend_Rest_Route构建RESTful API。对于文件上传,我应该使用PUT还是POST来处理该过程?我试图尽可能一致地定义REST动词。请参阅:PUT或POST:故事的其余部分
我的理解是,仅当我更新指定资源的全部内容时,才应该使用PUT。我必须知道要使用PUT的确切URL。另一方面,如果我发送一个命令到服务器来创建指定资源的下属,使用一些服务器端算法,则应该使用POST。
假设这是用于上传图像的REST API。这是否意味着如果服务器要操作图像文件(即创建缩略图,调整大小等),我应该使用POST;如果我只想将原始图像文件保存到服务器,则应使用PUT?
如果我使用PUT来处理文件上传,应该按以下步骤进行:
1.用户发送GET请求以检索通过PUT上传文件的特定URL。 2.然后,用户向该URL发送PUT请求。
正在上传的文件是原始的-正是用户上传的文件。
我对这个东西非常新,请确保我在这里说得有意义...
如果您知道最佳方法,请随时发表评论。
4个回答

159
这里似乎存在一些误解。PUT与POST不是真正意义上的替换与创建,而是关于幂等性和资源命名的区别。
PUT是一个幂等操作。它需要提供资源的名称和实体作为该资源内容(可能包含服务器生成的添加部分)。重复执行PUT操作应该与只执行一次或二十次结果相同,某种程度上的相同(不必是逐字节完全相同,但用户提供的信息应该保持完整)。你永远不会希望PUT触发财务交易。
POST是非幂等操作。你不需要提供你要创建的资源的名称(POST也不必须要创建;如果希望将资源去重,也可以使用POST)。POST通常用于实现“创建一个带有新名称的资源并告诉我名称”的操作——由“新名称”所暗示的非幂等性符合这一点。当创建一个新资源时,在Location头中发送资源定位器是完全正确的事情。
如果你采取的政策立场是客户端永远不应该创建资源名称,那么POST就成为了创建的完美选择(尽管理论上它可以根据提供的实体执行任何操作),而PUT则是如何进行更新操作。对于许多RESTful应用程序来说,这非常有意义,但并非所有应用都是如此;如果向用户呈现的模型是文件系统,则要求用户提供资源名称是非常合理的,这时PUT将成为主要的创建操作(而POST则被委托给像创建空目录等不太常见的操作;WebDAV可以进一步减少对POST的需求)。
总而言之:不要从创建/更新的角度来考虑问题,而是应该从谁创建资源名称以及哪些操作具有幂等性的角度来考虑。PUT实际上是创建或更新操作,而POST则是执行任何不能随意重复的操作。

2
太棒了。非常好的解释,感谢您花时间详细阐述! - FloatingRock

14

3

REST不是一项标准,因此这很容易变成一场宗教战争。 AtomPub和OData被认为是“符合REST的”标准,它们确实达成了共识: POST = 创建,而PUT = 更新。


4
PUT和POST与REST没有任何关系。它们是HTTP RFC的一部分,所以我不明白为什么PUT vs POST的争论应该变成任何形式的战斗。 - Suresh Kumar
1
@Suresh,但不知何故它确实可以 :) 例如,AtomPub和OData都表示您不能使用PUT来创建不存在的内容。这与您答案中的引语不同。 - Robert Levy
@Suresh,请参考 https://dev59.com/HHRB5IYBdhLWcg3wa2q2 中的所有争论。 - Robert Levy

0
简单的答案是,在您的情况下,应该使用PUT而不是POST,因为您将替换整个文件内容。请参阅PUT vs POST
“我必须知道要PUT的确切URL”
不需要知道PUT的URI,即在PUT操作之前不需要存在PUT URI。如果资源不存在,则创建该资源。如果资源已经存在,则使用新表征替换资源。
引用链接文章:
“PUT在特定的URL上放置页面。如果已经有一个页面,则完全替换它。如果没有页面,则创建一个新页面。这意味着它类似于DELETE,然后插入具有相同主键的新记录。”

3
听起来,PUT 的功能受限。通常需要使用服务器端算法来处理上传的文件。例如,对于图片,服务器可能需要调整其大小;对于文档,算法可能需要重命名它们以创建不同版本。如果我理解正确,对于 PUT 而言,是用户定义资源名称。我不确定这是否是个好主意。 - woran
1
@woran:通常不建议用户定义资源名称,但并非普遍如此。(此外,您可以基于内容的哈希值进行版本控制,以便两次PUT相同内容只会产生一个版本,保留幂等性规则。) - Donal Fellows

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