RESTful创建单例资源的规范探讨:POST与PUT的选择
作为经常和REST API打交道的开发者,我来聊聊这类单例资源(比如用户专属档案)的API设计规范问题——这确实是很多人容易混淆的点,毕竟平时我们接触更多的是集合类资源的接口。
首先先明确:单例资源指的是在特定上下文(比如已认证用户的上下文)中,只会存在一个实例的资源,比如个人档案、用户的默认收货地址这类。接下来针对你的问题逐一解答:
一、创建单例资源:选POST还是PUT?
核心判断标准是:客户端是否能提前确定该资源的唯一标识符(URI)。
用
POST /profile的场景:
当客户端无法提前确认/profile这个URI对应的资源是否存在时,适合用POST。比如用户刚注册完成,还没有创建过个人档案,客户端只是请求服务器“帮我创建我的专属档案”,服务器负责生成并维护这个单例资源的URI,创建成功后返回201 Created,同时在Location头中返回资源URI。
这种方式符合POST的语义:提交一个请求,让服务器创建一个新的、由服务器分配标识符的资源。用
PUT /profile的场景:
当客户端明确知道/profile就是自己的专属资源地址(比如系统默认给每个用户预生成了空档案),这时候可以用PUT。PUT的语义是将指定URI的资源设置为请求体中的状态——如果资源不存在,服务器就创建它;如果已经存在,就替换它。而且PUT是幂等的,多次调用同一个请求,结果和一次调用完全一致,这在表单重复提交这类场景下很友好。
举个实际例子:
- 场景A:用户注册后,系统引导用户“完善个人档案”,这时候用
POST /profile更合理,因为用户是第一次创建,客户端不确定资源是否存在。 - 场景B:用户登录后,直接进入档案编辑页面(系统已经为用户生成了空档案),用户编辑后提交,这时候用
PUT /profile更合适,因为客户端明确知道这个URI对应的就是自己的档案。
二、资源创建后是否可修改,会影响方法选择吗?
会有影响,但不是绝对的,核心还是要贴合HTTP方法的语义:
如果资源是创建后只读的:
那只能用POST来创建。因为PUT的语义是“替换资源状态”,如果资源不允许修改,用PUT就违背了它的语义——总不能允许客户端用PUT创建,却拒绝后续的PUT修改吧?这种情况下,POST创建成功后,后续对/profile的PUT/PATCH请求应该返回405 Method Not Allowed。如果资源是可修改的:
两种方法都可以选,但要保持语义一致:- 若用POST创建,后续修改可以用
PUT /profile(替换整个资源)或PATCH /profile(部分更新); - 若用PUT创建,后续修改继续用PUT即可(因为PUT本身就支持“不存在则创建,存在则替换”的逻辑)。
- 若用POST创建,后续修改可以用
三、PUT的幂等性要求,是否意味着资源创建后必须支持更新?
答案是完全不是。
PUT的幂等性定义是:多次调用同一个PUT请求,产生的效果和调用一次完全相同,和资源是否允许更新没有必然联系。
举个极端例子:如果业务规则是“个人档案创建后就不能修改”,那:
- 客户端第一次发送
PUT /profile,服务器创建资源,返回201 Created; - 如果客户端再次发送完全相同的PUT请求,服务器应该返回
200 OK或204 No Content,但不会修改资源(因为资源已经存在且状态和请求体一致)——这依然符合幂等性; - 如果客户端发送不同内容的PUT请求,服务器应该返回
403 Forbidden或409 Conflict,多次发送这个请求的结果都是“拒绝修改”——这也不违反幂等性,因为多次调用的结果一致。
所以PUT的幂等性要求,只需要保证“相同请求多次调用结果一致”,不需要强制资源支持修改。
内容的提问来源于stack exchange,提问作者samfrances

