zoukankan      html  css  js  c++  java
  • 谁说 HTTP GET 就不能通过 Body 来发送数据呢?

    一、简介

      当我们被问及 HTTP 的 GET 与 POST 两种请求方式的区别的时候,很多答案是说 GET 的数据须通过 URL 以 Query Parameter 来传送,而 POST 可以通过请求体来发送数据,所以因 URL 的受限,往往 GET 无法发送太多的字符。这个回答好比在启用了 HTTPS 时,GET 请求 URL 中的参数仍然是明文传输的一样。

      GET 果真不能通过 Request Body 来传送数据吗?非也。如此想法多半是因循着网页中 form 的 method 属性只有 get 与 post 两种而来。因为把 form 的 method 设置为 post, 表单数据会放在 body 中,而 method 为 get(默认值) 时, 提交时浏览器会把表单中的字符拼接到 action 的 URL 后作为 query parameter 传送。于是乎就有了这么一种假像:HTTP GET 必须通过 URL 的查询参数来发送数据。

      其实 HTTP 规范并未规定说 GET 就不能发送 body 数据,在 RFC GET 中只是说:The GET method means retrieve whatever information (in the form of an entity) is identified by the Request-URI.只是说 GET 意味着通过 URI 来识别资源。

    二、测试

      我也是本着传统上对 GET 与 POST 区别的误解很多年,今天突然意识到 GET 应该可以使用 body, 况且 HTTP 本身是一个纯文本的协议。没有测试就没有 100% 的发言权,所以做了如下的测试:

      在一个 Spring Boot Web 项目中创建的 GET 请求 API

    1 @RestController
    2 public class DemoController {
    3  
    4     @RequestMapping(value = "/", method = RequestMethod.GET)
    5     public String getRequest(@RequestParam("id") String id, @RequestBody String body) {
    6         return id + ": " + body;
    7     }
    8 }

      上而创建的 GET 请求,URL 是 /?id=something, 然后希望通过 request body 来获得请求数据

      再来一个测试用例,给 GET 请求发送 body 数据

     1 @RunWith(SpringRunner.class)
     2 @WebMvcTest
     3 public class DemoControllerTest {
     4  
     5     @Autowired
     6     private MockMvc mockMvc;
     7  
     8     @Test
     9     public void shouldReturnDefaultMessage() throws Exception {
    10         this.mockMvc.perform(get("/?id=100").content("Hello, Get Body"))
    11             .andDo(print())
    12             .andExpect(content().string(is("100: Hello, Get Body")));
    13     }
    14 }

      上面的单元测试顺利通过,说明对于 GET 请求我们同样可以使用 Request Body 来发送数据,而且 Spring 的测试框架也支持 GET 发送 body 数据

      再作一个验证,curl 命令, 需要用 -X 指定为 GET 请求,否则 curl 在使用 -d 发送 body 数据时自动切换为 POST 请求

      通过  curl -v 可以看到详细的请求响应数据,两个请求的 Content-Length 都是 8, 即 "Get Body" 的长度,它们确实是在 Request Body 中,服务端接送 GET 来的 body 数据也没有半点问题。

      下面是通过 Wireshark 捕获到的数据包的样子

      如果说通过 Spring 的测试用例以及 curl 命令还有所疑问的话,看上面那张图片就分明的告诉我们是在使用 GET 发送 body 数据的。

      但确实有些工具或类库不让我们发送 GET 请求时设置 Body, 例如著名的 Postman, 在选择 GET 时 Body 标签是灰色不可用的。

      而且从目前最新的 Apache Http Client 4.5 组件,它的 HttpGet 也不支持设置 Request Body, 因为 HttpGet 没有像 HttpPost 那样的 setEntity(entity) 方法。

      另一个 OkHttpClient 库也不支持 GET 发送 Request Body, 当执行下面的代码时

    1 new Request.Builder()
    2    .url("http://localhost:8080/?id=100")
    3    .method("GET", RequestBody.create(MediaType.parse("application/json"), "hello body"))
    4    .build();

      直接告诉我

    1 java.lang.IllegalArgumentException: method GET must not have a request body

      最后再试一个 AsyncHttpClient 库

    1 Dsl.asyncHttpClient()
    2    .prepareGet("http://localhost:8080/?id=100")
    3    .setBody("Get Body")
    4    .execute()
    5    .toCompletableFuture()
    6    .thenAccept(System.out::println).join();

      输出 "100: Get Body", 证明 AsyncHttpClient 是可以 GET 时发送 Body 数据的。

    本文来自博客园,作者:Mr-xxx,转载请注明原文链接:https://www.cnblogs.com/MrLiuZF/p/15133243.html

  • 相关阅读:
    中文词频统计及词云制作 25
    实验一 DOS实验 25
    字符串练习 25
    Python、循环的练习 25
    用requests库和BeautifulSoup4库爬取新闻列表 25
    爬取新闻列表 25
    Mockito使用总结
    20121116
    20121123
    20121115
  • 原文地址:https://www.cnblogs.com/MrLiuZF/p/15133243.html
Copyright © 2011-2022 走看看