REST API标准实现:获取Widget资源,不存在则创建
符合REST规范的解决方案
首先必须明确:GET请求绝对不能触发资源创建——REST规范里GET被定义为「安全方法」,即不会改变服务器状态的操作,客户端、缓存系统都依赖这个约定,所以在GET里做创建逻辑是违反规范的,绝对不能这么干。
符合规范的正确思路是利用PUT请求+条件请求头,具体步骤如下:
客户端先发送
GET widget/bob尝试获取目标资源:- 如果返回200,直接使用响应内容即可;
- 如果返回404,说明资源不存在,继续下一步。
客户端发送
GET widget/template获取模板数据。客户端携带模板数据,向
widget/bob发送PUT请求,同时加上If-None-Match: *请求头:- 服务器收到请求后,检查
If-None-Match: *的条件:只有当widget/bob不存在时,才用模板数据创建该资源,返回201 Created; - 如果资源已经存在(比如在步骤1到3之间被其他客户端创建了),服务器会返回412 Precondition Failed,此时客户端再重新发送
GET widget/bob即可获取已有资源。
- 服务器收到请求后,检查
这个方案完全符合REST规范:
- PUT语义是「将目标资源设置为请求体的状态」,且是幂等操作(重复调用结果一致);
- 条件请求头
If-None-Match: *保证了只有资源不存在时才执行创建,避免了不必要的副作用; - 所有操作都围绕「Widget资源」展开,没有自定义操作型端点,符合REST的资源导向原则。
另外补充:如果不想让客户端分两步(先GET模板再PUT),可以让服务器支持直接在PUT请求中指定使用模板创建——比如客户端发送PUT请求时,请求体携带{"useTemplate": true},服务器内部判断:如果资源不存在,就用预设模板初始化;如果已存在,返回409 Conflict或者直接返回已有资源(根据业务需求定),但这种方式需要服务器额外处理请求体的标识,而用条件请求头的方式更贴合HTTP标准语义。
再回头看你提到的三个方案:
- 方案1用POST+条件头:POST不是幂等操作,且语义上POST通常用于服务器生成ID的资源创建,这里客户端已知ID,用PUT更合适;
- 方案2的PUT思路是对的,加上条件请求头就完全符合规范了;
- 方案3的自定义
widget/initialize端点属于「操作导向」,不符合REST的「资源导向」原则,不推荐。
内容的提问来源于stack exchange,提问作者user210757
相关产品推荐
相关产品推荐

