基础
软件开发,不同系统之间最常见的数据交互协议是HTTP,客户端【发起请求】并【接收服务端的响应】,服务端【收到请求】并【响应】。
一个HTTP请求分为 【请求行】【请求头】【请求体】三部分,详情参见这里。
【请求行】里包含一个URL,该URL可以包含query component部分,即?之后的部分。
【请求行】里还包含本次请求的方式,HTTP常用的请求方式有GET和POST。前者用于客户端获取数据,后者用户客户端提交数据至服务端。二者之间的详细区别见这里。
传参
在发起请求的时候,可以携带参数传递给服务端。
GET请求没有请求体,参数只能随URL传递(常见)或随请求头传递(不常见,工程中的请求头一般都是统一封装,为每个请求都设置差异化的请求头比较繁琐)。
GET方式的请求参数以query component的形式传递。query string更加常用,即 query string ≈ query component。
POST方式用于将数据发送给服务器,发送的数据置于请求体中(body),而body中的内容类型由Content-Type请求头指定。
Content-Type
The Content-Type entity header is used to indicate the
media type.
Content-Type这个请求头/响应头用于表明资源的媒体类型。
-
In requests, (such as POST or PUT), the client tells the server what type of data is actually sent.
作为请求头,客户端通过该值告知服务端实际发送的数据类型。 -
In responses, a Content-Type header tells the client what the content type of the returned content actually is.
作为响应头,服务端通过该值告知客户端响应体中内容的类型。
MIME
上文提到,Content-Type的值是MIME type。
A MIME type (now properly called "media type", but also sometimes "content type") is a string sent along with a file indicating the type of the file (describing the content format, for example, a sound file might be labeled audio/ogg, or an image file image/png).
MIME类型(通常称为“媒体类型”,有时也称为“内容类型”)是与文件一起发送的字符串,用于指定文件类型(描述内容格式,例如,声音文件对应为audio/ogg,图像文件对应为image/png)。
常见的有:
-
application/json:表明内容是Json字符串,参见这里和RFC 4627 -
application/x-www-form-urlencoded:键值组由&分割,键与值由=分割,键与值中的非数字字母字符将被百分比编码。因此,该类型不适用与二进制数据传输,参见这里 -
multipart/form-data:每个值作为数据块(body part)发送,客户端代理定义的分隔符(boundary)将每个part分开。key由每个part的Content-Disposition标头中给出。 text/plain- ...
Servlet
Java EE中,Servlet致力于同客户端进行通信。关于Servlet,可以参见这一篇文章。
HttpServletRequest
采用Spring MVC框架,可以将HTTP请求中的信息以一定的方式转换并绑定到控制器类的方法参数中,称之为Spring MVC的数据绑定。
当客户端请求的参数比较简单时,方法形参可以直接使用Spring MVC提供的默认参数类型进行数据绑定,常见的默认类型参数如下:
-
HttpServletRequest:Http请求的Java封装,该接口继承自ServletRequest -
HttpServletResponse:Http响应的Java封装 HttpSessionModel/ModelMap
我们这里讨论HTTP参数的接收,因此重点关注HttpServletRequest接口。
该接口由Servlet容器实例化并传递给目标Servlet的doGet/doPost方法,常用方法有:
-
public String getHeader(String name);获取指定请求头 -
public String getMethod();获取请求方式,GETorPOST... -
public String getQueryString();获取queryString,即URL后由?分割的部分。如果不存在,则返回null -
public Part getPart(String name) throws IOException,ServletException;获取指定名称的part,若不存在返回null。若请求不是multipart/form-data则抛出ServletException
ServletRequest
由上文可知,通过HttpServletRequest接口可以获取到客户端发起的HTTP请求的【请求头】【请求方法】【queryString】等信息。现在继续研究其父类ServletRequest。
ServletRequest提供了客户端请求目标Servlet的信息,提供的信息有parameter name and values, attributes, and an input stream..
ServletRequest接口由Servlet容器实例化并传递给目标Servlet的service方法,常用方法有:
-
public String getCharacterEncoding();获取request body中数据的编码方式 -
public int getContentLength();获取request body中的input stream的bytes的长度 -
public String getContentType();获取request body中的Content Type -
public ServletInputStream getInputStream() throws IOException;使用ServletInputStream以二进制数据的形式检索请求的主体。可以调用此方法或getReader来读取request body中的内容 public String getParameter(String name);获取指定的请求参数,若不存在,则返回null。请求参数是请求的额外信息,对于Http Servlet,请求参数存在于queryString或posted form data
Spring MVC数据绑定
由前文讨论可知,理论上,Controller中的方法只有一个HttpServletRequest参数就能够或取到本次请求的所有信息,它相当于一个参数容器。但请求中的参数过多的时候, 势必会存在许多取参的样板代码。
Spring MVC取参过程做了优化。
采用Spring MVC框架,可以将HTTP请求中的信息以一定的方式转换并绑定到控制器类的方法参数中,称之为Spring MVC的数据绑定。
详细的绑定原理及源码分析可以参考这篇文章,本文只讨论具体的操作方法。
服务端接收
参数来源有两个:
-
ServletRequest#getParameter(String name);取出queryString或posted form data中的参数 -
ServletRequest#getInputStream();取出request body中的二进制数据
相应的,Spring MVC提供了两种类型的绑定方式
- 不使用注解、或配合
@RequestParam注解,可绑定默认类型(前文所述四种)、简单数据类型(Integer、Double...)、POJO类型、包装POJO、数组、集合 -
@RequestBody注解将请求体中的所有内容映射为一个Java对象,此时request body常见的Content-Type是application/json,即请求体里的数据是一个json str
客户端传参
开发中常见的客户端有 jquery ajax、axios、Post Man、Retrofit
其中,ajax和axios都提供了配置类方便自定义。
ajax的请求参数只能配置在data(Data to be sent to the server.)属性中;
axios则提供了params和data两个属性用于配置请求参数,data中的内容作为request body发送,而params则是随请求一起发送的普通参数。
其他
- 如果
key1=value1&key1=value2&key3=value3,则Spring MVC支持将将其绑定为名为key1的数组和名为key1的集合(需要使用@RequestParam注解),HTTP自身允许; - 如果
key1=value1,value2,value3,则Spring MVC支持将其绑定为名为key1的数组和名为key1的集合(需要使用@RequestParam注解),Spring MVC的能力扩展; - 如果
key1=value1,value2,value3&key1=value4&key1=value5,则Spring MVC支持将其绑定为key1的数组和集合(需要@requestParam注解),结果有3个元素,第一个元素是value1,value2,value3; - 如果queryString 的
key1=value1但form data的key1=value2,则最终绑定的结果按参数类型而定:如果是String,则value1,value2;如果是数字,则是value1(即queryString优先);如果是容器,则包含两个元素; - js客户端发送请求时指定
Content-Type为multipart/form-data的时候,要借助于FormDataAPI。
HTTP请求中的form data和request payload的区别