HTTP报文
HTTP请求流程
HTTP超文本传输协议(HyperText Transfer Protocol)是一种用于分布式、协作式和超媒体信息系统的应用层协议。
HTTP是基于客户/服务器模式,且面向连接的。典型的HTTP事务处理有如下的过程:
(1)客户与服务器建立连接;
(2)客户向服务器提出请求;
(3)服务器接受请求,并根据请求返回相应的文件作为应答;
(4)客户与服务器关闭连接。
HTTP报文
用于HTTP协议交互的信息被称为HTTP报文。请求端的HTTP报文叫请求报文,响应端的叫响应报文。
请求报文
HTTP 请求报文由请求行、请求头部、空行 和 请求包体 4 个部分组成。
请求行:请求行由请求方法字段、URL 字段 和HTTP 协议版本字段 3 个部分组成,他们之间使用空格隔开。
请求头部:请求头部由关键字/值对组成,每行一对,关键字和值用英文冒号“:”分隔。请求头部通知服务器有关于客户端请求的信息。
空行:最后一个请求头之后是一个空行,发送回车符和换行符,通知服务器以下不再有请求头;
报文体:报文主体和首部字段之间通过一个空行分隔,请求主体中包含了要发送给 Web 服务器的数据(一般 POST 请求都会包含请求主体,GET 请求参数都在 URL 里面,请求主体一般为空),响应主体中包含了服务器返回给客户端的数据,一般是 HTML 文档或者 JSON 格式数据。
响应报文
HTTP 响应报文由状态行、响应头部、空行 和 报文体 4 个部分组成。
状态行:状态行由 HTTP 协议版本字段、状态码和状态码的描述文本 3 个部分组成,他们之间使用空格隔开;
响应头部:响应头相关信息;
空行:最后一个响应头部之后是一个空行,发送回车符和换行符,通知服务器以下不再有响应头部。
报文体:服务器返回给客户端的信息;
HttpMessageConverter
疑问
在上面我们了解到了HTTP是使用报文的方式进行数据传输的。
在Spring MVC中,我们接收请求参数和响应数据,都是直接使用的对象,那么框架肯定是帮我们处理了报文,包括解析报文为对象,对象解析为报文。
converter包
处理HTTP转换相关的代码在spring框架的spring-web模块下的converter包中。
HttpMessageConverter接口
HttpMessageConverter就是HTTP报文消息转换器,可以将报文转换为JAVA对象,或者将JAVA对象转换为报文。
它定义了一些读写报文的相关方法。
public interface HttpMessageConverter<T> {
boolean canRead(Class<?> var1, @Nullable MediaType var2);
boolean canWrite(Class<?> var1, @Nullable MediaType var2);
List<MediaType> getSupportedMediaTypes();
default List<MediaType> getSupportedMediaTypes(Class<?> clazz) {
return !this.canRead(clazz, (MediaType)null) && !this.canWrite(clazz, (MediaType)null) ? Collections.emptyList() : this.getSupportedMediaTypes();
}
// 从给定的输入消息中读取给定类型的对象,并返回它。
T read(Class<? extends T> var1, HttpInputMessage var2) throws IOException, HttpMessageNotReadableException;
// 将给定的对象写入给定的输出消息。
void write(T var1, @Nullable MediaType var2, HttpOutputMessage var3) throws IOException, HttpMessageNotWritableException;
}
HttpMessageConverter有很多实现接口及子类,支持多种消息转换方式。
下面列述几种比较常用的转换器:
转换器 | 描述 |
---|---|
FormHttpMessageConverter | 负责读取form提交的数据(能读取的数据格式为 application/x-www-form-urlencoded,不能读取multipart/form-data格式数据);负责写入application/x-www-from-urlencoded和multipart/form-data格式的数据 |
SourceHttpMessageConverter | 负责读取资源文件和写出资源文件数据 |
ByteArrayHttpMessageConverter | 可以读写字节数组 |
AbstractXmlHttpMessageConverter | XML 的转换 |
ObjectToStringHttpMessageConverter | 用于将字符串内容与目标对象类型进行相互转换 |
ProtobufHttpMessageConverter | 读取和写入 com.google.protobuf.Messages使用 谷歌协议转换器 |
GsonHttpMessageConverter | Gson 转换器 |
MappingJackson2HttpMessageConverter | Jackson 2.x 读取和写入 JSON |
注解支持
HttpMessageConverter提供了@RequestBody及@ResponseBody注解用于报文体转换。
@RequestBody
@RequestBody可以根据请求的内容类型解析为方法参数。
也就是可以获取请求体,在控制器方法设置一个形参,使用@RequestBody进行标识,当前请求的请求体就会为当前注解所标识的形参赋值。
GET方式无请求体,所以使用@RequestBody接收数据时,前端不能使用GET方式提交数据,而是用POST方式进行提交。
@RequestBody主要用来接收前端传递给后端的json字符串中的数据的(请求体中的数据)。
@Target(ElementType.PARAMETER)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface RequestBody {
boolean required() default true;
}
案例:
1、 编写一个控制器方法,Post请求,形参添加注解@RequestBody,表示将请求报文转为User对象;
@PostMapping("/testRuquestBody")
public Object testRuquestBody(@RequestBody User user) {
return user;
}
1、 发送Post请求,这里注意,需要传递application/json格式的数据,并绑定到请求体中;
@ResponseBody
@ResponseBody用于标识一个控制器方法,可以将该方法的返回值直接作为响应报文的响应体响应到浏览器。
@ResponseBody注解的作用是将controller的方法返回的对象通过转换器转换为指定的格式之后,写入到response对象的body区,通常用来返回JSON数据或者是XML数据。
注意:在使用此注解之后不会再走视图处理器,而是直接将数据写入到输入流中,他的效果等同于通过response对象输出指定格式的数据。
从4.0 版本开始,这个注解也可以在类型级别添加,在这种情况下它是继承的,不需要在方法级别添加。
案例:
1、 编写一个@Controller控制器方法,不添加@ResponseBody注解时,发现,MVC会走视图处理器,认为这个控制器返回的是视图名称;
2、 添加了@ResponseBody注解后,字符串直接被解析为报文响应给了浏览器;
@RestController
@RestController注解是springMVC提供的一个复合注解,标识在控制器的类上,就相当于为类添加了@Controller注解,并且为其中的每个方法添加了@ResponseBody注解。
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Controller
@ResponseBody
public @interface RestController {
@AliasFor(annotation = Controller.class)
String value() default "";
}
相关类支持
Spring MVC也提供了一些类,可以用来表示报文实体
HttpEntity
HttpEntity类表示一个 HTTP 请求或响应实体,由头部和报文体组成,其泛型T表示报文内容。
private final HttpHeaders headers;
@Nullable
private final T body;
RequestEntity
RequestEntity继承自HttpEntity,主要是添加了 HTTP 方法和 目标 URL属性。
RequestEntity表示封装请求报文的一种类型,需要在控制器方法的形参中设置该类型的形参,当前请求的请求报文就会赋值给该形参,可以通过getHeaders()获取请求头信息,通过getBody()获取请求体信息。
案例:
1、 编写一个@Controller控制器方法,直接在形参设置RequestEntity类型,指定泛型为User;
@PostMapping("/testRequestEntity")
public Object testRequestEntity(RequestEntity<User> requestEntity) {
HttpMethod method = requestEntity.getMethod();
URI url = requestEntity.getUrl();
Type type = requestEntity.getType();
User body = requestEntity.getBody();
HttpHeaders headers = requestEntity.getHeaders();
return body;
}
1、 可以看到RequestEntity接受了请求报文的相关信息;
ResponseEntity
RequestEntity继承自HttpEntity,主要是添加了添加 {@link HttpStatus} 状态代码。
ResponseEntity用于控制器方法的返回值类型,该控制器方法的返回值就是响应到浏览器的响应报文。
案例:
1、 编写一个@Controller控制器方法,返回ResponseEntity类型,指定泛型为User;
@GetMapping("/testResponseEntity")
public ResponseEntity<User> testResponseEntity() {
User user = new User();
user.setName("吃个桃桃");
user.setAge(15);
return new ResponseEntity<>(user, HttpStatus.OK);
}
1、 测试发现,Body中的数据和HttpStatus直接返回;
版权声明:本文不是「本站」原创文章,版权归原作者所有 | 原文地址: