我正在为我们的应用程序开发一个新的RESTful Web服务。

当对某些实体执行GET时,客户端可以请求实体的内容。如果他们想添加一些参数(例如排序列表),可以在查询字符串中添加这些参数。

或者,我希望人们能够在请求主体中指定这些参数。HTTP/1.1似乎并没有明确禁止这一点。这将允许他们指定更多信息,可能会更容易指定复杂的XML请求。

我的问题:

这完全是个好主意吗?HTTP客户端在GET请求中使用请求体时会遇到问题吗?

https://www.rfc-editor.org/rfc/rfc2616


当前回答

如果您真的想将可计算的JSON/XML正文发送到web应用程序,那么放置数据的唯一合理位置是使用RFC4648:Base64Encoding和URL和文件名安全字母表编码的查询字符串。当然,您可以只对JSON进行URL编码,并将其放入URL参数的值中,但Base64给出的结果较小。请记住,URL大小有限制,请参阅不同浏览器中URL的最大长度是多少。

您可能会认为Base64的padding=字符可能对URL的参数值有害,但这似乎不是-请参阅以下讨论:http://mail.python.org/pipermail/python-bugs-list/2007-February/037195.html . 但是,您不应该将编码数据放在没有参数名称的位置,因为带填充的编码字符串将被解释为具有空值的参数键。我会用类似的东西_b64=<编码器数据>。

其他回答

REST作为协议不支持OOP,Get方法就是证明。作为解决方案,您可以将DTO序列化为JSON,然后创建查询字符串。在服务器端,您将能够将查询字符串反序列化为DTO。

看看:

ServiceStack中基于消息的设计使用WCF构建基于RESTful消息的Web服务

基于消息的方法可以帮助您解决Get方法的限制。您可以将任何DTO作为请求主体发送

Nelibur web服务框架提供了您可以使用的功能

var client = new JsonServiceClient(Settings.Default.ServiceAddress);
var request = new GetClientRequest
    {
        Id = new Guid("2217239b0e-b35b-4d32-95c7-5db43e2bd573")
    };
var response = client.Get<GetClientRequest, ClientResponse>(request);

as you can see, the GetClientRequest was encoded to the following query string

http://localhost/clients/GetWithResponse?type=GetClientRequest&data=%7B%22Id%22:%2217239b0e-b35b-4d32-95c7-5db43e2bd573%22%7D

根据RFC 2616第4.3节“消息正文”:

服务器应读取并转发任何请求的消息体;如果请求方法不包括实体实体的定义语义,则在处理请求时应忽略消息体。

也就是说,服务器应该始终从网络中读取任何提供的请求体(检查内容长度或读取分块体等)。此外,代理应该转发他们收到的任何此类请求。然后,如果RFC为给定方法的主体定义了语义,那么服务器实际上可以使用请求主体来生成响应。然而,如果RFC没有定义主体的语义,那么服务器应该忽略它。

这与上面Fielding的引用一致。

第9.3节“GET”描述了GET方法的语义,没有提到请求体。因此,服务器应该忽略它在GET请求中收到的任何请求体。

关于一个老问题的想法:

在正文中添加完整的内容,在查询字符串中添加正文的短哈希,这样缓存就不会有问题(如果正文内容发生变化,哈希值会发生变化),并且您可以在需要时发送大量数据:)

如果您真的想将可计算的JSON/XML正文发送到web应用程序,那么放置数据的唯一合理位置是使用RFC4648:Base64Encoding和URL和文件名安全字母表编码的查询字符串。当然,您可以只对JSON进行URL编码,并将其放入URL参数的值中,但Base64给出的结果较小。请记住,URL大小有限制,请参阅不同浏览器中URL的最大长度是多少。

您可能会认为Base64的padding=字符可能对URL的参数值有害,但这似乎不是-请参阅以下讨论:http://mail.python.org/pipermail/python-bugs-list/2007-February/037195.html . 但是,您不应该将编码数据放在没有参数名称的位置,因为带填充的编码字符串将被解释为具有空值的参数键。我会用类似的东西_b64=<编码器数据>。

哪个服务器会忽略它?–2012年8月30日21:27

例如,谷歌做得比忽视它更糟糕,它会认为这是一个错误!

用一个简单的netcat自己试试:

$ netcat www.google.com 80
GET / HTTP/1.1
Host: www.google.com
Content-length: 6

1234

(1234内容后面是CR-LF,总共6个字节)

你会得到:

HTTP/1.1 400 Bad Request
Server: GFE/2.0
(....)
Error 400 (Bad Request)
400. That’s an error.
Your client has issued a malformed or illegal request. That’s all we know.

您还可以从Bing、Apple等获得400个Bad Request,这些请求由AkamaiGhost提供。

因此,我不建议对主体实体使用GET请求。