首页 文章

带请求正文的HTTP GET

提问于
浏览
1533

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

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

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

我的问题:

  • 这完全是一个好主意吗?

  • HTTP客户端在GET请求中使用请求主体会有问题吗?

http://tools.ietf.org/html/rfc2616

17 回答

  • 3

    根据XMLHttpRequest,它无效 . 来自standard

    4.5.6 send()方法客户端 . send([body = null])发起请求 . 可选参数提供请求正文 . 如果请求方法是GET或HEAD,则忽略该参数 . 如果未打开任何状态或设置了send()标志,则引发InvalidStateError异常 . send(body)方法必须运行以下步骤:如果未打开state,则抛出InvalidStateError异常 . 如果设置了send()标志,则抛出InvalidStateError异常 . 如果请求方法是GET或HEAD,则将body设置为null . 如果body为null,请转到下一步 .

    虽然,我认为不应该因为GET请求可能需要大量的内容 .

    因此,如果您依赖浏览器的XMLHttpRequest,它很可能无法正常工作 .

  • 7

    我'm upset that REST as protocol doesn' t支持OOP和 Get 方法是证明 . 作为解决方案,您可以将DTO序列化为JSON,然后创建查询字符串 . 在服务器端,您可以将查询字符串反序列化为DTO .

    看看:

    基于消息的方法可以帮助您解决Get方法限制 . 您可以像请求正文一样发送任何DTO

    Nelibur web service framework provides functionality which you can use

    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
    
  • 241

    Roy Fielding's comment about including a body with a GET request .

    是的 . 换句话说,任何HTTP请求消息都允许包含消息体,因此必须解析消息 . 但是,GET的服务器语义受到限制,使得正文(如果有的话)对请求没有语义含义 . 解析的要求与方法语义的要求是分开的 . 所以,是的,您可以使用GET发送一个正文,不,这样做永远不会有用 . 这是HTTP / 1.1的分层设计的一部分,一旦规范被分区(正在进行中),它将再次变得清晰 . 罗伊....

    是的,您可以使用GET发送请求正文,但它不应该有任何意义 . 如果您通过在服务器上解析它并根据其内容更改响应来赋予它意义,那么您在the HTTP/1.1 spec, section 4.3中忽略了此建议:

    [...]如果请求方法不包含实体主体的定义语义,则在处理请求时应该忽略消息主体 .

    the HTTP/1.1 spec, section 9.3中的GET方法的描述:

    GET方法意味着检索Request-URI标识的任何信息([...]) .

    其中声明请求主体不是GET请求中资源标识的一部分,只是请求URI .

  • 21

    既不是restclient也不是REST console支持这个,但卷曲确实如此 .

    HTTP specification在第4.3节中说

    如果请求方法的规范(第5.1.1节)不允许在请求中发送实体主体,则消息主体不得包含在请求中 .

    Section 5.1.1将各种方法重定向到第9.x节 . 他们都没有明确禁止包含消息体 . 然而...

    Section 5.2

    通过检查Request-URI和Host头字段来确定Internet请求标识的确切资源 .

    Section 9.3

    GET方法意味着检索Request-URI标识的任何信息(以实体的形式) .

    这一点一起表明,在处理GET请求时,服务器不需要检查Request-URI和Host头字段之外的任何其他内容 .

    总之,HTTP规范并不会阻止您使用GET发送消息体,但是如果所有服务器都不支持它,那么它就不会让我感到惊讶 .

  • 37

    恕我直言,您可以在 URL 中发送 JSON 编码(即 encodeURIComponent ),这样您就不会违反 HTTP 规范并将 JSON 发送到服务器 .

  • 4

    你可以发送一个GET与一个正文或发送一个POST并放弃RESTish宗教信仰(它不是那么糟糕,5年前只有一个信仰的成员 - 他的评论在上面联系) .

    两者都不是很好的决定,但发送GET机构可以防止某些客户端和某些服务器出现问题 .

    执行POST可能会遇到一些RESTish框架的障碍 .

    Julian Reschke建议上面使用像“SEARCH”这样的非标准HTTP标头,这可能是一个优雅的解决方案,除了它更不可能得到支持 .

    列出能够和不能完成上述各项工作的客户可能是最有效的 .

    客户那个不能发送身体GET(我知道):

    • XmlHTTPRequest Fiddler

    可以使用正文发送GET的客户端:

    • 大多数浏览器

    可以从GET检索主体的服务器和库:

    • Apache

    • PHP

    从GET中剥离主体的服务器(和代理):

  • 1292

    Elasticsearch接受带有正文的GET请求 . 它甚至似乎是首选方式:http://www.elasticsearch.org/guide/en/elasticsearch/reference/current/common-options.html#_request_body_in_query_string

    某些客户端库(如Ruby驱动程序)可以在开发模式下将cry命令记录到stdout,并且它正在广泛使用此语法 .

  • 16

    虽然你可以做到这一点,因为它不希望事情以这种方式发挥作用 . HTTP请求链中有许多阶段,虽然它们符合HTTP规范,但您只能考虑透明代理,加速器,A / V工具包等事情 . )

    这是Robustness Principle背后的精神_B5954_,你不想在没有充分理由的情况下突破规范的界限 .

    但是,如果你有充分的理由,那就去吧 .

  • 5

    我不建议这样做,它违背了标准做法,并没有提供那么多回报 . 你想保持身体的内容,而不是选择 .

  • 4

    如果您真的想将可缓存的JSON / XML主体发送到Web应用程序,那么放置数据的唯一合理位置是使用RFC4648: Base 64 Encoding with URL and Filename Safe Alphabet编码的查询字符串 . 当然你可以只是urlencode JSON并将put放在URL param的值中,但Base64会给出较小的结果 . 请注意,有URL大小限制,请参阅What is the maximum length of a URL in different browsers? .

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

  • 5

    例如,它适用于Curl,Apache和PHP .

    PHP文件:

    <?php
    echo $_SERVER['REQUEST_METHOD'] . PHP_EOL;
    echo file_get_contents('php://input') . PHP_EOL;
    

    控制台命令:

    $ curl -X GET -H "Content-Type: application/json" -d '{"the": "body"}' 'http://localhost/test/get.php'
    

    输出:

    GET
    {"the": "body"}
    
  • 13

    您尝试实现的目标已经使用更常见的方法完成了很长时间,并且不依赖于使用GET的有效负载 .

    您可以简单地构建特定的搜索媒体类型,或者如果您想要更加RESTful,请使用类似OpenSearch的内容,并将请求POST到服务器指示的URI,例如/ search . 然后,服务器可以生成搜索结果或构建最终URI并使用303重定向 .

    这具有遵循传统PRG方法的优点,有助于缓存中介缓存结果等 .

    也就是说,无论如何,URI都会被编码为非ASCII的任何东西,application / x-www-form-urlencoded和multipart / form-data也是如此 . 如果您的目的是支持ReSTful场景,我建议使用此而不是创建另一种自定义json格式 .

  • 4

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

    例如 Google 比忽略它更糟糕,它会认为它是 error

    使用简单的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请求与body实体一起使用 .

  • 26

    来自RFC 2616, section 4.3,"Message Body":

    服务器应该在任何请求上读取和转发消息体;如果请求方法不包含实体主体的定义语义,那么在处理请求时应该忽略消息主体 .

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

    这符合上面Fielding的引用 .

    Section 9.3,"GET"描述了GET方法的语义,并没有提到请求体 . 因此,服务器应该忽略它在GET请求上收到的任何请求主体 .

  • 123

    那么不合格的base64编码头呢? “SOMETHINGAPP-PARAMS:sdfSD45fdg45 / AS”

    长度限制hm . 你不能让你的POST处理区分意义吗?如果你想要简单的参数,比如排序,我不明白为什么这会是一个问题 . 我想你确实很担心 .

  • 62

    如果您尝试利用缓存,则可能会遇到问题 . 代理人不会在GET主体中查看参数是否会对响应产生影响 .

  • 22

    我把这个问题提交给了IETF HTTP WG . Roy Fielding(1998年http / 1.1文件的作者)的评论是这样的

    “......除了解析和丢弃该机构以外,还可以执行任何其他操作”

    RFC 7213(HTTPbis)状态:

    “GET请求消息中的有效负载没有定义的语义;”

    现在似乎很清楚,目的是禁止GET请求体上的语义,这意味着请求体不能用于影响结果 .

    如果您在GET上包含一个正文,那么会有代理以各种方式破坏您的请求 .

    总而言之,不要这样做 .

相关问题