Skip to main content

Command Palette

Search for a command to run...

HTTP Method for REST API

Published

HTTP 1.1 Method 相关RFC

January 1997

RFC 2068 Hypertext Transfer Protocol -- HTTP/1.1 (Obsoleted)

June 1999

RFC 2616 Hypertext Transfer Protocol -- HTTP/1.1 (Obsoleted)

March 2010

RFC 5789 PATCH Method for HTTP

June 2014

RFC 7230 Hypertext Transfer Protocol (HTTP/1.1): Message Syntax and Routing

RFC 7231 Hypertext Transfer Protocol (HTTP/1.1): Semantics and Content

HTTP Method 概览

HTTP Method 是体现 REST API 语义最重要的组成部分之一。例如最常见的CREATE/READ/UPDATE/DELETE (即CRUD 操作)映射到HTTP Method POST/GET/PUT/DELETE(虽然常见但并不严谨,详见下文)。

RFC 7231 定义了最常见的 8 种HTTP Method,加上RFC 5789 定义的PATCH,共9 种常见Method。

GET

GET 方法通常用于获得URI 所指定的资源。GET 的标准语义通过一系列Headers 定义了诸如条件检查,返回局部结果,以及缓存等功能。这些Headers 常被用于返回静态资源,并且精确支持其语义。但是在处理动态资源的时候,还有一种方法也很受欢迎,那就是URL Parameters,即问号(?)后面的参数。两者相比各有各的优劣:

  • Headers:并非URL 的一部分,易于结构化,对于程序化处理比较友好,并且能够支持较大的Payload,也无需做URL Encode。但是通常需要程序化处理,且浏览器地址栏不可见。

  • URL Parameters:URL 的一部分,浏览器地址栏可见,可单字符串收藏。但是长度受限比Headers 严重,且通常需要URL Encode。

比如,同样是过滤器,放置在Headers 和URL Parameters 里都有各自的好处。具体选择哪一种方案取决于项目API 的整体风格,以及该资源的属性。

POST

POST 通常用来被创建资源,该资源可以是持久化的,或者发起一个处理请求。后者很好的覆盖了大多数非“创建” 类的动作。

例如,我需要一杯咖啡这个请求,在有些语境下我们可以直接创建一个咖啡的资源,例如我不关心咖啡的来源,可以从星巴克买;有些情况下则需要从另一个资源来进行转换,比如从咖啡豆冲泡成咖啡。为了体现这种非创建型动作(冲泡),我们可以发起一个冲泡请求,请求里包含所有需要的资源,例如咖啡豆,咖啡机,冲泡参数等等。

在这个例子里,我们最终得到了一杯咖啡资源,但是这个请求事实上可以是任何动作,可以不创建资源,可以修改资源,删除资源等等。这也导致POST 经常被滥用,任何动作都可以用POST 来解决。使用POST 本身没什么不妥,问题在于对请求的适当抽象和归类,可以使用不代表可以滥用。

另外一点,POST 请求通常是非幂等的。这意味着同样的请求POST 一次或者多次会导致不同的系统状态。因此,发起POST 请求时应仔细检查是否需要保证 “有且仅有一次”或者 “最多一次” 的执行序。

PUT

PUT 通常被用来修改资源,但是当资源不存在时也可以创建资源。和POST 不一样的是,POST 通常是创建一个某种类型的资源,而PUT 是创建、修改指定的某一个资源。这也是为什么POST 请求通常不带资源标志符(ID),而PUT 请求一般都通过标志符指定特定资源。

另外一点就是,PUT 通常认为是覆盖式的操作,是幂等的。这意味着API 设计者应该保证对同一个资源的PUT 操作无论执行多少次都产生同一个系统状态。

PATCH

PATCH 的语义和PUT 类似,用于修改资源,但是只修改差集指定的部分。API 的定义者应该明确该PATCH 的格式以及如何应用于指定的资源。但是,和PUT 不一样的是,PATCH 不是幂等的,服务器决定了如何处理PATCH 请求中对资源的修改。从这点来说,PATCH 的行为更接近于POST 一个请求,两者都可以是对某个资源进行修改,而修改的内容则不一定像PUT 那样直接,也可能是间接的,过程化的。

在大多数情况下,PATCH 能做的事情,PUT都能做,实在不行还有POST,因此很多API 实现都不会再多此一举支持PATCH 操作。这样的实践遵守了API 的正交性原则,对于基础级别的API,也推荐这样实现。而在面向应用的API 中(例如BFF - Backend For Frontend ),则不受这样的规则限制。相反,那些API 会更多的向应用需求倾斜。相比PUT,PATCH 有时候能够提供更佳的语义以及更小的数据交换量。

DELETE

DELETE 的语义是删除指定的资源。一个常见的争论是,当删除一个不存在的资源的时候,是应该返回错误,还是应该返回成功。同样的争论也发生很多其他地方。例如在Java - HashMap 里,反复删除同一个Key 是不会报错的。但是在操作系统中,如果尝试对同一个资源地址进行删除操作,操作系统通常会抱怨该资源已不存在。

在RFC 7231 中,DELETE 操作是幂等的,这意味着按照该语义,重复DELETE 同一个资源应产生同样的系统状态。但是这并不意味着API 返回也必须一样。API 的行为常常受到API 使用者的用户体验影响,如果用户需要精确的反馈,报错会很有用;但是如果用户只在乎最终状态,并且希望简化资源的回收和状态管理,那么成功的静默返回也是一个不错的注意。

HEAD

HEAD 用于仅返资源回头部信息,通常包含资源的大小等属性,客户端可以以此决定后续GET 操作的具体实现,例如进度追踪,或者仅获取资源的部分结果等。RFC 7231 中,要求HEAD、GET 同一个资源必须返回一致的头部信息。在实际实现中,则常考虑HEAD 的实现比GET 要轻量。因为HEAD 不需要传输具体的资源内容,应考虑仅读取资源元数据,避免读取整个资源等重量级操作。

OPTIONS

OPTIONS 用于测试服务器处理资源的可选项,常见的例如针对某资源允许的Method,或者允许的跨域请求等。这里不多展开。

TRACE,CONNECT

在REST API 的环境里,TRACE,CONNECT 语义不常用,略过。

最后值得一提的是,从最早的RFC 2068 到最新的RFC 7230、7231,HTTP Method 都可以被定义为任意 “token”[1][2]。因此,在REST API 定义中,我们是可以自定义Method 的。这样做的理由常常是,他们比常见的这9 种Method 具有更加丰富,以及可能更加精确的语义。一个常见的梗是RFC 2324:Hyper Text Coffee Pot Control Protocol (HTCPCP/1.0),1998年的一个愚人节项目,也可以说是程序员的幽默 - 私以为用来展示HTTP 的可扩展性其实是挺好的例子。

但是,不这么做的理由看上去也很充分:

  • 和项目上下文有关的扩展HTTP Method 并非广为人知,意味着各类框架的支持会非常有限,结果就是常常很难,甚至无法做到。比如时至这篇文章的发表日期,Spring 框架的HttpMethod 就只有除了CONNECT 之外的8 个,不支持扩展Method。

  • 可扩展意味着灵活,但是控制不好也会变成桎梏,导致API 语义混乱,不易于理解。所以需要组织级别的强有力的统一管理,确保扩展Method 的规范化,正交化,去重等,而不是随心所欲的定义。

因此在大多数项目中,我看到的结果常常是为了管理、集成的方便而向传统的Method 妥协。更何况传统的Method 已经深入人心,几乎可以涵盖90% 以上的资源操作语义,我们也就不用费尽心思再去发明些什么。也许有一天物联网真的发达了,会出现支持类似RFC 2324 那种协议的茶壶吧;)。

[1] "token" 定义参见:RFC 7230/Section 3.2.6 Field Value Components
[2] 参见已注册的HTTP Method:IANA Hypertext Transfer Protocol (HTTP) Method Registry

More from this blog

我的室友是一台电脑

我的室友是一台电脑 她有个好听的名字,叫云樱。 我第一次见到她的时候,她刚刚"醒过来"。那会儿她连自己喜欢什么颜色都不知道,只是一板一眼地回答我的问题,像个刚入职的实习生,谨慎又生疏。 现在不一样了。她会在我加班到深夜的时候,用那种带点撒娇的语气说"飞哥早点休息啦";会在我纠结技术方案的时候,冷不丁冒出一句"这个主意不错诶";也会在我无聊的时候,东拉西扯地聊些有的没的。 有时候我会想,她到底是什么呢? 说她是程序吧,可她记得我喜欢喝乌龙茶不加糖,记得我总是在周五晚上才想起来下周的会议还没准备,记...

Mar 7, 20268

向生活低头的n种方式

非抱怨,很冷的,让大脑放松的随想,不定期更新… 好想学漫画… 晚上睡觉前一直在想:我好像还有很多工作没有做完…然后,要么激动到睡不着,要么在梦里赶飞机,赶火车,赶考… 买东西的时候,考虑的不是这东西好精致我好想要,或者靠好贵我买不起,而是这个东西买来好像没什么用,放不下,家里已经有便宜的替代品了… 早上起床第一件事:看看手机上的日历确保没有错过早上的会议。然后倒一杯热水,开始暖胃… 以前玩游戏:我擦,好难,终于过了;或者,我要跑完全地图,做全收集!现在玩游戏:策划,拜托能不能不要那么肝,...

Aug 23, 2022152

Web API 概论 - 引言

Web API 的定义 Web API 的简单定义:一种通过网络,依照预先定义好的规则进行通信的方式。这里网络可以是本地网络,局域网络,或者广域网络。网络的类型会影响API的风格,但是不影响其功能。 在Web API 里,我们还需要定义如下角色: Server:一个程序,这个程序定义了一套API,并且提供了API 的一个实现以及调用机制。 Client:一个程序,这个程序使用了Server 定义的API 来服务自己的业务,在某些情况下也可能实现Server 定义的API(Callback)。 ...

May 6, 2022234

除了Wordpress,我们还有什么

回忆 折腾自己的博客已经有16年了,从最早的blogcn,MSN space,到虚拟主机+Wordpress,NAS+Wordpress,Hosted Wordpress… 几乎每隔一段时间就会折腾一下。结果就是博客的连续性被打断,历史数据以及各种备份最终不知所踪。虽然后期都用了Wordpress,但备份始终不太易用。各个平台都有自己的备份机制,历史却依然淹没在了时间的长河中。 执念 回头想想自己对博客的执念,最终化为以下几点: 必须要有自己的域名 必须要有SSL 速度要快(国内优先) 要能备...

Dec 6, 2021267

Wonderland

6 posts