基础
软件开发,不同系统之间最常见的数据交互协议是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封装 HttpSession
Model/ModelMap
我们这里讨论HTTP参数的接收,因此重点关注HttpServletRequest
接口。
该接口由Servlet容器实例化并传递给目标Servlet的doGet/doPost
方法,常用方法有:
-
public String getHeader(String name);
获取指定请求头 -
public String getMethod();
获取请求方式,GET
orPOST
... -
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
的时候,要借助于FormData
API。
HTTP请求中的form data和request payload的区别