zoukankan      html  css  js  c++  java
  • Spring中的HTTP请求与响应实体(以及 entity 与 body 的区别)

    0、基本概念

    报文(message):

    HTTP的一个请求或响应叫做报文(message),是HTTP通信的基本单位,分为请求报文(request message)和响应报文(response message)两类。

    报文由起始行(start line)、首部(header)和可选的主体(body)三部分(其实还包含header之后、body之前的空行CRLF。即使没有header或body,也应该有一个CRLF)。

    首部(header):

    首部分为通用首部、请求首部、响应首部、实体首部、扩展首部5类。

    在Spring中,表示header的类为HttpHeaders,HttpHeaders是MultiValueMap<String, String>的子类,说明一个header可以有多个值。

    主体(body):

    主体是HTTP报文的载荷(payload),即HTTP要传输的内容。它包含实际的数据,对于一些请求(如GET请求)或响应可能不存在body。

    主体又称为报文主体(message body)或实体主体(entity body),在Spring中用泛型表示,说明可以为任意类型。在没有传输编码时, 报文主体等于实体主体。

     

    1、实体(entity)

    实体包括实体首部(entity header)和实体主体(entity body)。entity的存在依赖于body,如果没有body,就没有了entity。

    通常情况下,即在没有传输编码时,实体只有实体主体,报文主体等于实体主体。只有当传输中进行编码操作时,实体主体的内容发生变化,才导致它和报文主体产生差异。在现在的HTTP协议下,传输编码只有“Transfer-Encoding: chunked”这一种。

    实体首部类型

    实体首部是指那些用来描述实体主体内容的首部,它告知报文接收者body的一些信息。实体首部包括3类:

    - 信息性首部:Allow(可对此body执行的请求方法),Location(即重定向中指出资源的位置)

    - 内容首部:说明内容的类型、size以及其他信息,比如很多以Content开头的首部(Content-Type、Content-Length、Content-Encoding)。

    - 实体缓存首部:说明如何或什么时候进行缓存,比如ETag、Expires、Last-Modified。

    实体首部的位置 

    当报文body没有进行编码时,实体首部就位于报文首部中,是报文首部的一部分;

    当报文body进行了编码,则报文首部和报文body中都会有实体首部。如下例子中,在传输中需要对body进行编码操作,以便传输表单内容:

    POST /upload HTTP/1.1
    Host: example.com
    Content-Length: xxx
    Content-Type: multipart/form-data; boundary=AaBbCcDd
    
    --AaBbCcDd
    Content-Disposition: form-data; name="username"
    
    RuphiLau
    --AaBbCcDd
    Content-Disposition: form-data; name="file"; filename="picture.jpg"
    Content-Type: image/jpeg
    
    ...(picture.jpg的数据)...
    --AaBbCcDd--

    在这个报文的首部和body中都有实体首部,而且该报文有多个实体(表单中的每段内容为一个实体),每个实体里有实体头部、实体主体,并过CR+LF分割。

    entity被payload取代

    另外,定义 entity 概念的RFC 2616,目前已经被 RFC 7230 到 7235 取代,术语实体(entity)被有效载荷(payload)代替。

    报文(message)和有效载荷(payload)的区别比较明显,另一个容易混淆的点是 message body 和 payload body。

    根据 RFC 7230:HTTP 报文的报文主体(message body)(如果存在的话)是用来运载请求或响应的有效载荷主体(payload body)的。除非应用了传输编码,报文主体等价于有效载荷主体。

    以分块传输编码(Chunked transfer encoding)的一个示例来解释message body与payload body的区别:

    HTTP/1.1 200 OK
    Content-Type: text/plain
    Transfer-Encoding: chunked
    
    25
    This is the data in the first chunk
    
    1C
    and this is the second one
    
    3
    con
    
    8
    sequence
    
    0

    示例中的payload body为 This is the data in the first chunk、and this is the second one、con 和 sequence 这几行。而message body为第一个空行以后的所有部分,除了有效载荷主体之外,还包括了 25、1C 等行和几个空行。

    Spring中的实体 

    在Spring中,有一个HttpEntity类,就表示HTTP请求实体,它有两个子类RequestEntityResponseEntity,分别表示请求实体和响应实体。

    不论是请求实体还是响应实体,entity 都包含首部(header)和主体(body)(对于GET请求,body可能为空)。

     

    2、RequestEntity 

    RequestEntity 的使用

    RequestEntity 是用于发起HTTP请求的实体,相对于HttpEntity,它增加HTTP请求方法、URL。

    RequestEntity 可以用在发起HTTP请求的客户端代码中,也可以用在处理HTTP请求的服务端代码中。

    1)HTTP客户端使用:在 RestTemplate 的 exchange() 方法中使用

    MyRequest body = ...
    RequestEntity<MyRequest> request = RequestEntity
        .post(new URI("https://example.com/bar"))
        .accept(MediaType.APPLICATION_JSON)
        .body(body);
    ResponseEntity<MyResponse> response = template.exchange(request, MyResponse.class);

    2)HTTP服务端使用

    在Spring MVC中,RequestEntity 可以作为 Controller 方法的入参:

    @RequestMapping("/handle")
    public void handle(RequestEntity<String> request) {
      HttpMethod method = request.getMethod();
      URI url = request.getUrl();
      String body = request.getBody();
    }

     

    RequestEntity 实例的创建

    RequestEntity 可以通过普通的构造方法进行实例化,其参数最全的构造方法为:

    public RequestEntity(@Nullable T body, @Nullable MultiValueMap<String, String> headers,
                @Nullable HttpMethod method, URI url, @Nullable Type type)

     

    RequestEntity 也可以通过Builder进行实例化。如 RequestEntity  的静态方法 get(URI url)、post(URI url) 等将会返回一个 HeadersBuilder<?> 或 BodyBuilder 实例,该实例包含了header信息,可以进一步设置其他的header。

    然后调用该 Builder 的 body()(有body情况下用于指定body) 或 build() 方法,创建指定的RequestEntity实例。

    // Create shared factory
    UriBuilderFactory factory = new DefaultUriBuilderFactory();
    
    // Use factory to create URL from template
    URI uri = factory.uriString("https://example.com/{foo}").build("bar");
    RequestEntity<MyRequest> request = RequestEntity.post(uri).accept(MediaType.APPLICATION_JSON).body(body);

     

    3、ResponseEntity

    ResponseEntity 的使用

    ResponseEntity 是HTTP响应实体,相对于父类HttpEntity,它增加了响应状态码。

    状态码用类HttpStatus表示,它包含了状态值(value,如200)和原因短语(reason phrase,如OK)。

    ResponseEntity 可以在HTTP客户端请求数据时使用,也可以在HTTP服务端处理请求时使用。

    1)HTTP客户端:通过 RestTemplate getForEntity()exchange() 方法请求数据时返回ResponseEntity

    ResponseEntity<String> entity = template.getForEntity("https://example.com", String.class);
    String body = entity.getBody();
    MediaType contentType = entity.getHeaders().getContentType();
    HttpStatus statusCode = entity.getStatusCode();

    2)HTTP服务端:在Spring的 Controller 方法中使用 ResponseEntity

    @RequestMapping("/handle")
    public ResponseEntity<String> handle() {
        URI location = ...;
        HttpHeaders responseHeaders = new HttpHeaders();
        responseHeaders.setLocation(location);
        responseHeaders.set("MyResponseHeader", "MyValue");
        return new ResponseEntity<String>("Hello World", responseHeaders, HttpStatus.CREATED);
    }

     

    ResponseEntity 实例的创建 

    与 RequestEntity 实例的创建类似,ResponseEntity 实例既可通过普通的构造方法创建;

    也可先通过对应某个响应状态的静态方法(如ok()、created(URI location)、status(int status)等),创建相应的BodyBuilder,然后进一步指定header或body,最后build出ResponseEntity实例。

     

    参考文档

     

  • 相关阅读:
    WPF中任务栏只显示主窗口
    makefile经典教程
    Linux常见指令大全
    ubuntu下 fdisk用法
    将SD系统启动卡恢复成普通卡
    1、采用SD启动盘bootingLinux
    Soc常见问题
    ARM Linux 3.x的设备树(Device Tree)
    DS-5获取License
    Soc EmbeddedDesign Suite (EDS)13.1.0.162安装
  • 原文地址:https://www.cnblogs.com/haycheng/p/12895759.html
Copyright © 2011-2022 走看看