我正在设计一个API来通过HTTP,我想知道是否使用HTTP POST命令,但只有URL查询参数,没有请求体,是一个很好的方法。

注意事项:

“好的网页设计”要求通过POST发送非幂等动作。这是非幂等的。 当请求参数出现在URL中时,更容易开发和调试这个应用程序。 该API并不打算广泛使用。 似乎要做一个没有正文的POST请求需要更多的工作,例如必须显式添加Content-Length: 0报头。 在我看来,没有正文的POST有点违背大多数开发人员和HTTP框架的期望。

在POST请求中通过URL查询而不是通过请求体发送参数还有什么缺点或优点吗?

编辑:考虑这一点的原因是操作不是幂等的,除了检索之外还有其他副作用。请参阅HTTP规范:

In particular, the convention has been established that the GET and HEAD methods SHOULD NOT have the significance of taking an action other than retrieval. These methods ought to be considered "safe". This allows user agents to represent other methods, such as POST, PUT and DELETE, in a special way, so that the user is made aware of the fact that a possibly unsafe action is being requested. ... Methods can also have the property of "idempotence" in that (aside from error or expiration issues) the side-effects of N > 0 identical requests is the same as for a single request. The methods GET, HEAD, PUT and DELETE share this property. Also, the methods OPTIONS and TRACE SHOULD NOT have side effects, and so are inherently idempotent.


当前回答

从编程的角度来看,对于客户端,它将参数打包并将它们附加到url上,并执行POST和GET操作。在服务器端,它计算来自查询字符串的入站参数,而不是发送的字节。基本上,这是一种洗涤。

可能存在的优点/缺点可能是特定的客户端平台如何在其网络堆栈中处理POST和GET例程,以及web服务器如何处理这些请求。根据您的实现,一种方法可能比另一种更有效。知道了这一点你才会做出决定。

尽管如此,从程序员的角度来看,我更倾向于允许在主体中包含所有参数的POST,或者在url上包含所有参数的GET,并且显式地忽略任何POST请求的url参数。这样可以避免混淆。

其他回答

REST阵营有一些指导原则,我们可以使用它们来标准化使用HTTP动词的方式。这在构建RESTful API时很有帮助。

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

换句话说,如果你的API操作改变了服务器状态,REST建议我们使用POST/PUT/DELETE,而不是GET。

用户代理通常知道做多个POST是不好的,并会对此发出警告,因为POST的目的是改变服务器状态(例如。在收银台付款),你可能不想这样做第二次!

与GET相比,你可以经常这样做(幂等)。

如果你的动作不是幂等的,那么你必须使用POST。如果你不这样做,你就是在自找麻烦。GET、PUT和DELETE方法必须是幂等的。想象一下,如果客户端预先获取您的服务的每个可能的GET请求,那么应用程序中会发生什么情况——如果这会导致客户端可见的副作用,那么一定是出了问题。

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

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

从编程的角度来看,对于客户端,它将参数打包并将它们附加到url上,并执行POST和GET操作。在服务器端,它计算来自查询字符串的入站参数,而不是发送的字节。基本上,这是一种洗涤。

可能存在的优点/缺点可能是特定的客户端平台如何在其网络堆栈中处理POST和GET例程,以及web服务器如何处理这些请求。根据您的实现,一种方法可能比另一种更有效。知道了这一点你才会做出决定。

尽管如此,从程序员的角度来看,我更倾向于允许在主体中包含所有参数的POST,或者在url上包含所有参数的GET,并且显式地忽略任何POST请求的url参数。这样可以避免混淆。

我发现在POST端点上使用查询参数是完全可以接受的,如果它们引用了必须通过POST端点更新的已经存在的资源(而不是创建的)。

例如:

POST /user_settings?user_id=4
{
  "use_safe_mode": 1
}

上面的POST有一个引用现有资源的查询参数,镜像GET端点定义以获得相同的资源。

body参数定义如何更新现有资源。

编辑:

我更喜欢这样,而不是像有些人建议的那样,让终点直接指向已经存在的资源:

POST /user_settings/4
{
...
}

原因有三:

我发现它有更好的可读性,因为查询参数是命名的,就像上面的“user_id”,而不是“4”。 通常,还有一个GET端点来获取相同的资源。在这种情况下,端点的路径和查询参数将是相同的,我喜欢这种对称性。 我发现,如果需要多个参数来定义已经存在的资源,嵌套会变得很麻烦,很难读取:

POST /user_settings/{user_id}/{which_settings_id}/{xyz}/{abc}/ ...
{
...
}

你想要理由吗?这里有一个:

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

来源:HTML 4.01标准,17.13节表单提交