带有URL查询参数的HTTP POST-好主意吗?[关闭]


451

我正在设计一个通过HTTP的API,我想知道是否使用HTTP POST命令,但仅使用URL查询参数,而没有请求主体,是一种不错的方法。

注意事项:

  • “良好的Web设计”要求通过POST发送非幂等动作。这是非幂等的动作。
  • 当请求参数出现在URL中时,开发和调试该应用程序会更加容易。
  • 该API并非旨在广泛使用。
  • 似乎没有主体地发出POST请求将花费更多的工作,例如Content-Length: 0必须显式添加标头。
  • 在我看来,没有主体的POST有点违反大多数开发人员和HTTP框架的期望。

通过URL查询而不是请求正文在POST请求上发送参数是否还有其他陷阱或优势?

编辑:正在考虑的原因是该操作不是幂等的,并且具有除检索之外的副作用。参见HTTP规范

特别是,已经建立了约定,即GET和HEAD方法不应具有除检索之外的其他任何操作。这些方法应该被认为是“安全的”。这允许用户代理以特殊方式表示其他方法,例如POST,PUT和DELETE,以便使用户知道请求了可能不安全的操作这一事实。

...

方法还可以具有“幂等”的特性,因为(错误或过期问题除外)N> 0个相同请求的副作用与单个请求的副作用相同。GET,HEAD,PUT和DELETE方法共享此属性。同样,方法OPTIONS和TRACE不应有副作用,因此本质上是幂等的。


11
如果您不打算在体内提供数据,为什么还要使用POST?
Sunny Milenov

114
因为该操作不是幂等的。
史蒂芬·胡维格

20
@Jared,请注意,从2.5年前开始,“ REST”一词并未出现在此问题中。:)关于幂等性的HTTP规范适用,无论Web服务的月度架构如何。幸运的是,此API设计用于代理的系统已经过时了。
史蒂芬·胡维格2011年

5
因为服务器日志不记录POST参数,但它们记录查询字符串。运行一系列的请求而不在浏览器中进行检测,然后查看回溯,要比单击这些请求要容易得多。此外,API并不是浏览器到服务器,而是服务器到服务器。最重要的是,无论如何,整个事件都是罐装的。:)
史蒂芬·休伊格

13
对于任何不知道幂等意味着什么的人:| restapitutorial.com/lessons/idempotency.html
Christopher Grigg

Answers:


259

如果您的操作不是幂等的,则必须使用POST。如果不这样做,您只是在寻求麻烦。 GETPUT并且DELETE方法必须是幂等的。想象一下,如果客户端预取GET了对服务的所有可能请求,应用程序中会发生什么–如果这会导致客户端可见副作用,那么出问题了。

我同意发送POST带有查询字符串但不带正文的似乎很奇怪,但是我认为在某些情况下它是合适的。

将URL的查询部分视为对资源的命令,以限制当前请求的范围。通常,查询字符串用于对GET请求进行排序或过滤(如?page=1&sort=title),但我认为它对a POST也要限制范围(例如?action=delete&id=5)是有意义的。


4
我为特定情况选择了此答案,但我认为R. Bemrose的论点对公共API很有说服力。
史蒂芬·休伊格

4
我认为他的回答绝对不正确。如果在将HTML页面发送到客户端时知道表单发布的URL参数,则可以将这些URL参数附加到表单的action属性上,否则JavaScript可以在提交表单时设置URL参数。
Don McCaughey

3
将XML文件发布到带有查询参数的url怎么样?那可能吗?
OpenCoderX

3
另一个例子:请求数据可以在http实体中,而请求的响应格式在查询参数(/action?response_format=json)中传递
rds 2015年

3
今天+1了。删除技术具有幂等性。如果实际上删除了该对象,那么您将得到一个未找到的404,因此服务器将具有相同的状态,但响应将有所不同。参见母牛图片:restapitutorial.com/lessons/idempotency.html
JPK

131

每个人都是正确的:对于非幂等请求,坚持使用POST。

如何同时使用URI查询字符串和请求内容呢?好吧,它是有效的HTTP(请参阅注释1),为什么不呢?

这也是完全合理的:URL(包括查询字符串部分)用于查找资源。HTTP方法动词(POST-及其可选的请求内容)用于指定操作或处理资源。这些应该是正交的关注。(但是,对于ContentType = application / x-www-form-urlencoded的特殊情况,它们并不是完美的正交关系,请参阅下面的注释2。)

注意1:HTTP规范(1.1)没有声明查询参数和内容对于接受POST或PUT请求的HTTP服务器是互斥的。因此,任何服务器都可以自由接受两者。即,如果您编写服务器,则没有什么可以阻止您选择接受两者(可能是不灵活的框架除外)。通常,服务器可以根据其所需的任何规则解释查询字符串。它甚至可以使用条件逻辑来解释它们,这些条件逻辑也引用其他标头,例如Content-Type,这导致注释2:

注意2:如果Web浏览器是人们访问您的Web应用程序的主要方式,而application / x-www-form-urlencoded是他们发布的Content-Type,那么您应该遵循该Content-Type的规则。而且application / x-www-form-urlencoded的规则更加具体(坦率地说,很不寻常):在这种情况下,您必须将URI解释为一组参数,而不是资源位置。[这与Powerlord提出的有用点相同;可能很难使用网络表单将内容发布到您的服务器。只是有所不同。]

注意3:查询字符串最初是做什么用的?RFC 3986将HTTP查询字符串定义为URI部分,它作为非分层方式定位资源。

万一提出这个问题的读者想问什么是好的RESTful体系结构:RESTful体系结构模式不需要URI方案以特定方式工作。RESTful体系结构将自身与系统的其他属性相关联,例如资源的可缓存性,资源本身的设计(其行为,功能和表示形式)以及是否满足幂等性。换句话说,就是实现一种与HTTP协议及其HTTP方法动词集高度兼容的设计。:-)(换句话说,RESTful体系结构对于资源的位置不太合适。)

最后要注意的是:有时查询参数还用于其他用途,既不查找资源也不编码内容。是否曾经见过像'PUT = true'或'POST = true'这样的查询参数?这些是不允许您使用PUT和POST方法的浏览器的解决方法。虽然这样的参数被视为URL查询字符串(上线)的一部分,我认为他们不是URL的查询的一部分精神


66

你想要理由吗?这是一个:

Web表单不能用于将请求发送到使用GET和POST混合使用的页面。如果将表单的方法设置为GET,则所有参数都在查询字符串中。如果将表单的方法设置为POST,则所有参数都在请求正文中。

资料来源:HTML 4.01标准,第17.13表格提交


10
这是一个不错的论据,但我认为现代浏览器的Javascript实现有点不足。我会考虑的-它以一种面向未来的方式引人注目。仅仅因为我现在不使用表单并不意味着我以后不再想要它。
史蒂芬·胡维格

9
将GET与POST混合只是一个非常糟糕的主意-严重破坏HTTP并且没有充分的理由。
aehlke

6
该摘录未出现在您链接到的页面上
Gareth 2010年

40
是的,但是method属性只是定义了如何在请求中包括“表单数据集”。当method是POST时,没有提及更改表单的URI action。而且任何URI当然都可以包含查询字符串部分。
Gareth 2010年

16
@Powerlord这是错误的。尝试使用例如的动作将表单设置为POST。/Books?bookCode=1234。Web服务器将获得POST形式的vars和查询字符串。
Jez

9

从程序的角度来看,对于客户端,它打包参数并将其附加到url上,并执行POST与GET。在服务器端,它从查询字符串而不是发布的字节中评估入站参数。基本上是洗。

可能有优点/缺点的地方可能是特定的客户端平台如何与它们的网络堆栈中的POST和GET例程一起使用,以及Web服务器如何处理这些请求。根据您的实现,一种方法可能比另一种更为有效。知道这一点将指导您在这里做出决定。

但是,从程序员的角度来看,我更喜欢允许正文中包含所有参数的POST或url中具有所有参数的GET,并明确地忽略任何POST请求的url参数。它避免了混乱。


8

我认为让查询参数标识URL上的资源,同时将内容有效载荷限制在POST正文中,可能仍然非常RESTful。这似乎将“我要发送什么?”的考虑分开。而不是“我要寄给谁?”。


5
问题不是关于REST。
史蒂芬·胡维格

3
@ user359996并非所有的HTTP API都是RESTful的。实际上,大多数声称实际上不是的API。同样,有趣的是,REST也不是仅HTTP。
阿列克·梅夫

4

REST阵营有一定的指导原则,我们可以用它来规范我们使用HTTP动词的方式。当您正在构建RESTful API时,这将很有帮助。

简而言之:GET应该是只读的,即对服务器状态没有影响。POST用于在服务器上创建资源。PUT用于更新或创建资源。DELETE用于删除资源。

换句话说,如果您的API操作更改了服务器状态,则REST建议我们使用POST / PUT / DELETE,但不要使用GET。

用户代理通常都知道执行多个POST是不好的,因此会发出警告,因为POST的目的是更改服务器状态(例如,在结帐时付款),并且您可能不想重复两次!

与您可以随意执行的GET(幂等)进行比较。


13
REST阵营说您应该使用HTTP规范中定义的HTTP。即RFC2616,仅此而已。
Darrel Miller

1
@Darrel引用ibm.com/developerworks/webservices/library/ws-restful:REST要求开发人员以与协议定义一致的方式显式使用HTTP方法。这项基本的REST设计原则在创建,读取,更新和删除(CRUD)操作与HTTP方法之间建立了一对一的映射。根据此映射:要在服务器上创建资源,请使用POST。要检索资源,请使用GET。要更改资源的状态或对其进行更新,请使用PUT。要删除或删除资源,请使用DELETE。
Saille

5
对不起,但这是完全错误的。REST需要符合统一的接口。如果使用HTTP,则该统一接口部分由RFC 2616定义。在该规范中,创建,读取,更新和删除与HTTP方法之间没有一对一的映射。
Darrel Miller

3
GET和DELETE可以很好地映射到CRUD中的Read和Delete,但是使用PUT / POST进行Update和Create并不那么简单。参见stackoverflow.com/questions/630453/put-vs-post-in-rest
dcstraw 2011年

5
回顾这6年后,鉴于该问题已被浏览了约10万次,我觉得值得对其进行小幅更新。根据Fielding对REST的定义(ics.uci.edu/~fielding/pubs/dissertation/rest_arch_style.htm),Darrel是正确的-没有提及将HTTP动词映射到CRUD。IBM的开发人员建议(上面的评论链接)反映了实现RESTful API的常规做法,而不是Fielding的REST定义。
Saille 2015年

-13

我同意-如果您只是在URL中而不是在正文中传递数据,则使用GET请求可能更安全。有关整个POST + GET概念的其他一些观点,请参见此类似问题


17
如果该操作有副作用,则使用GET方法肯定不是“安全”的,因为浏览器假定所有GET都是幂等的。
dcstraw 2011年

搜索引擎也会在噩梦中将其转换,因为Google会安全地“点击”带有GET请求的所有链接,但会省略其他所有内容。离开服务并不是很安全,以至于无辜的爬网程序可能会意外擦除数据库。
亚历杭德罗
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.