使用POST而不是GET的REST API


76

假设服务提供了一些我可以像这样使用的功能:

GET /service/function?param1=value1&param2=value2

我可以在POST查询中使用它吗?

POST /service/function { param1 : value1, param2 : value2 }

这两个查询是否相同?我可以在任何情况下使用第二种变体,或者文档中应明确指出可以同时使用GET和POST查询?


4
对此没有通用的答案-它取决于各个实现。并且GET并且POST 应该具有不同的语义,因此也许一般的答案是“我希望不要”
Damien_The_Unbeliever 2013年

2
REST并function不能很好地相处。如果URL包含functionmethodcommand,我会闻到RPC

1
如果您的目标是隐藏url结构本身的复杂性,请不要打扰。如果您要遵循RESTful原则POSTPOST则使用一种仅清理方法就被滥用
Kristian 2013年

2
没有遵循标准的HTTP API中对此没有通用的答案。你想做什么,就可以做什么。如果它是RESTful的,那么如果未记录该资源的作用,则无法执行POST。事实上,如果它是RESTful的,则必须使用HATEOAS,并且您不会对任何内容进行意外的请求。
Pedro Werneck

即使您使用不同的HTTP动词,也通常可以得到相同的最终结果。它仅取决于路由控制器内部的内容和返回值。等等。不过,遵循约定还是不错的。
secretthysnacks

Answers:


42

您不能单独使用APIusing,POST或者GET不能单独使用它们来调用它们。就像您的API说

/service/function?param1=value1&param2=value2

通过使用GET方法进行访问。POST如果POST创建者未将其指定为method,则无法使用method调用它。如果这样做,您可能会获得405 Method not allowed身份。

通常,在POST方法中,您需要以content-typeex的标头中描述的指定格式以正文形式发送内容。application/json用于json数据。

之后,请求主体在服务器端反序列化。因此,您需要传递来自客户端的序列化数据,并且由服务开发人员决定。

但是一般来说,GET当服务器向客户端返回一些数据并且对服务器没有任何影响时,POST通常使用它,而在服务器上创建一些资源。因此,一般情况下不应相同。


应该切断验证content-type头吗?如果标题是标题Content-Type: application/x-www-form-urlencoded,内容是标题JSON怎么办?
Suhail Gupta

但是在GET请求中,URL的长度受到限制(最大URL长度为2048个字符)。因此,如果我想向具有可能为长字符串(JSON)的参数的API发送请求,则应该使用POST而不是GET?
戈迪

@gordie,是的,如果您的API请求是大JSON,则应该使用POST,它可以发送请求正文。通常, GETAPI不需要那么多参数或JSON请求。
萨钦

67

只是为了进行审查,REST它具有开发人员应该遵循的某些属性才能使其RESTful

什么是REST?

根据维基百科:

REST体系结构样式描述了应用于体系结构的以下六个约束,同时使各个组件的实现可以自由设计:

  • 客户端服务器:服务器不关心用户界面或用户状态,因此服务器可以更简单,更可扩展。
  • 无状态:客户端与服务器之间的通信进一步受到限制,因为请求之间没有客户端上下文存储在服务器上。
  • 可缓存的:响应必须隐式或显式地将自己定义为可缓存的,以防止客户端响应其他请求而重用陈旧或不适当的数据。
  • 分层系统:客户端通常无法确定它是直接连接到最终服务器还是中​​间连接。中间服务器可以通过启用负载平衡和提供共享缓存来提高系统可伸缩性。
  • 按需代码(可选):服务器可以通过传输可执行代码来临时扩展或定制客户端的功能。
  • 统一接口:下文讨论的客户端和服务器之间的统一接口简化并解耦了体系结构,使每个部分都可以独立发展。(即HTTP GET,POST,PUT,PATCH,DELETE)

动词应该做什么

SO用户Daniel Vasallo很好地在理解REST:动词,错误代码和身份验证问题中列出了这些方法的职责:

处理类似以下的URI时:http : //example.com/resources/

GET:列出集合的成员,并带有其成员URI以便进一步导航。例如,列出所有待售汽车。

PUT:定义为“将整个集合替换为另一个集合”。

POST:在集合中创建一个新条目,其中ID由集合自动分配。创建的ID通常包含在此操作返回的数据中。

删除:定义为“删除整个集合”的含义。

因此,回答您的问题:

我可以在POST查询中使用它吗?...

这两个查询是否相同?我可以在任何情况下使用第二种变体,或者文档中应明确指出可以同时使用GET和POST查询?

如果您正在编写一个普通的旧RPC API调用,则它们在技术上可以互换,只要两个调用之间的处理服务器端没有区别即可。但是,为了使调用为RESTful,通过GET方法调用端点应具有与POST方法(用于创建新资源)不同的功能(即获取资源)。

旁注:关于是否POST也应允许使用它们来更新资源,存在一些争议……尽管我没有对此发表评论,我只是告诉你有些人对此有疑问。


6
因此,当我们出于各种原因(URL长度限制,许多框架中不支持GET的主体等)而希望使用其他动词而不是GET来检索实体列表时,REST API规范似乎还无法满足现实情况的需要。 )。这意味着,有许多hacky,不一致的解决方案可解决此问题,而没有指导开发人员的规范。
JustAMartin19年

61

由于以下原因,我将POST正文用于任何非平凡的业务应用程序:

  1. 安全性-如果我们将GET与查询字符串和https一起使用,则查询字符串可以保存在服务器日志中并作为引荐链接转发。服务器和网络管理员以及用户离开您的应用后前往的下一个域现在都可以看到这两个域。因此,如果我们发送包含机密PII数据(例如客户名称)的查询,则可能不希望这样做。
  2. URL最大长度-没什么大问题,但是某些浏览器对长度有限制。因此,如果我们的URL中有几个项目,例如查询,分页,要返回的字段等...。
  3. 默认情况下不缓存POST。有人说需要缓存。但是,在缓存超时之前,针对那个确切客户的那个确切对象的那个完全相同的搜索条件集会出现多少次?

顺便说一句,我也将字段返回到POST正文中,因为我可能不想公开自己的字段名称。安全就像洋葱。它有很多层,让我们哭泣!


3
无论请求类型如何,查询字符串通常都保存在Web服务器日志中。如果您认为POST因为看不到某些东西而更加安全,那么您就错了。缓存是完全不同的东西。
菲尔(Phil)

9
我认为斯科特的观点是,通过使用代替GET POST,你不必使用查询字符串在所有
Nexus

2
不赞成投票,根据OP如何对其进行标记,该问题专门针对REST。在这种情况下,这个答案是无关紧要的,因为它绝对不是REST。
内森·休斯

在这种情况下,我们如何区分POST调用是创建对象还是获取响应?
Noushad

不幸的是,Angular的Http Service不允许使用GET传输主体,当站点托管在接受GET主体的Web服务器上时,这将解决问题!
Dave Boal

14

想一想。当您的客户端向URI X发出GET请求时,对服务器的意思是:“我想要表示位于X处的资源,并且此操作不应更改服务器上的任何内容。” 一个PUT请求说:“我希望您用在请求正文中给您的新实体替换X处的任何资源”。DELETE请求说:“我希望您删除X处的任何资源”。PATCH表示“我正在给您这个差异,您应该尝试将其应用于X处的资源,并告诉我它是否成功。” 但是POST却说:“我正在向您发送该数据,该数据从属于X处的资源,我们已经就您应该如何使用它达成了事先协议。”

如果您没有在某个地方记录该资源,而该资源需要POST并对其进行处理,则向它发送POST并期望其像GET一样没有意义。

REST依赖于基础协议的标准化行为,而POST正是用于未标准化操作的方法。GET,PUT和DELETE请求的结果在标准中已明确定义,而POST未明确定义。POST的结果从属于服务器,因此,如果没有记录,可以使用POST进行操作,则必须假定不能这样做。


10

REST给HTTP动词(如其定义)带来了意义,但我更喜欢Scott Peal。

这也是WIKI对POST请求的扩展说明中的项目:

有时HTTP GET甚至不适合数据检索。例如,当需要在URL中指定大量数据时。浏览器和Web服务器可以限制它们处理的URL的长度,而不会被截断或错误。URL和查询字符串中保留字符的百分比编码会大大增加它们的长度,而Apache HTTP Server可以处理URL中最多4,000个字符,[5] Microsoft Internet Explorer限制为任何URL中2,048个字符。[6] 同样,在必须将敏感信息(例如用户名和密码)与其他数据一起提交以完成请求的情况下,不应使用HTTP GET。即使使用HTTPS,也可以防止在传输过程中拦截数据,浏览器历史记录和Web服务器的 的日志可能包含纯文本的完整URL,如果其中任何一个系统被黑客入侵,则可能会暴露这些URL。在这些情况下,应使用HTTP POST。[7]

我只能建议REST团队考虑更安全地使用HTTP协议,以避免使消费者难以接受不安全的“良好做法”。


1
Scott Peal的答案相比,这确实没有提供新的东西。您仅引用了wiki / provided和链接,并对此进行了说明:尽管链接可以回答问题,但最好在此处包括答案的基本部分并提供链接以供参考。如果链接的页面发生更改,仅链接的答案可能会失效。
Murmel '17

3

在REST中,每个HTTP动词都有其位置和含义。

例如,

  • GET用于获取URL中指向的“资源”。

  • POST是为了构造后端以“创建” URL中指向的“类型”资源。您可以在POST调用的正文中用参数或其他数据补充POST操作。

在这种情况下,由于您对使用查询“获取”信息感兴趣,因此它应该是GET操作而不是POST操作。

Wiki可能有助于进一步澄清问题。

希望有帮助!


2

如果我正确理解了这个问题,他需要执行REST GET操作,但想知道是否可以通过HTTP POST方法发送数据。

正如Scott早些时候在回答中很好地说明的那样,有许多充分的理由来进行POST输入数据。恕我直言,如果解决方案的质量是重中之重,则应采用这种方式。

不久前,我们创建了一个REST API来对用户进行身份验证,并使用用户名/密码并返回访问令牌。该API在TLS下进行了加密,但可以公开访问公共互联网。在评估了不同的选项之后,我们选择HTTP POST作为“ GET访问令牌”的REST方法,因为这是满足安全标准的唯一方法。


1

如果有特殊原因并可以正确处理,则可以使用POST代替GET有效。我了解它不是专门针对RESTy的,但是如果您的数据中有很多空格,“&”和斜杠等(例如,像Amazon这样的产品模型),那么尝试编码和解码可能会比实际值麻烦得多,而不仅仅是对其进行预JSON化。请确保返回正确的响应代码并大量注释您在做什么,因为它不是POST的典型用例。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.