重磅来袭:Spring 之 RequestBody 的使用姿势小结
SpringMVC 中处理请求参数有好几种不同的方式,如我们常见的下面几种
根据 HttpServletRequest 对象获取
根据 @PathVariable 注解获取 url 参数
根据 @RequestParam 注解获取请求参数
根据 Bean 的方式获取请求参数
根据 @ModelAttribute 注解获取请求参数
对上面几种方式有兴趣的可以看一下这篇博文: SpringMVC 之请求参数的获取方式
除了上面的几种方式之外,还有一种 @RequestBody 的使用方式,本文则主要介绍这种传参的使用姿势和相关注意事项
I. 使用姿势
1. 服务接口
借助 Spring 框架,使用 @RequestBody 并没有什么难度,很简单的就可以写一个使用 case 出来,如下
看上面的实现,和我们通常的写法并无差别,无非是将以前的 @RequsetParam 注解换成 @RequsetBody 注解,而且这个注解内部只有一个 filed,比 RequsetParam 还少
看到上面的实现,估计也可以猜出,这个注解对于后端而言,写没啥问题,关键是如何用(具体来讲是如何给前端用)
2. 接口调用
上面写完了,接下来的重点就是如何使用了,在使用之前,有必要了解下 RequestBody 这个注解出现的原有以及应用场景(换句话说它和 RequestParam 有什么区别,为什么要单独地搞一个这个东西出来)
RequestBody
@requestBody 注解常用来处理 content-type 不是默认的 application/x-www-form-urlcoded 编码的内容,比如说:application/json 或者是 application/xml 等。一般情况下来说常用其来处理 application/json 类型。
a. content-type 定义
在进入下一步之前,有必要说一下 Content-Type 这个 http 请求头的作用了,下面一段来自其他博文,原文链接见最后
MediaType,即是 Internet Media Type,互联网媒体类型;也叫做 MIME 类型,在 Http 协议消息头中,使用 Content-Type 来表示具体请求中的媒体类型信息。
常见媒体格式如下:
text/html : HTML 格式
text/plain :纯文本格式
text/xml : XML 格式
image/gif :gif 图片格式
image/jpeg :jpg 图片格式
image/png:png 图片格式
以 application 开头的媒体格式类型:
application/xhtml+xml :XHTML 格式
application/xml : XML 数据格式
application/atom+xml :Atom XML 聚合格式
application/json : JSON 数据格式
application/pdf :pdf 格式
application/msword : Word 文档格式
application/octet-stream : 二进制流数据(如常见的文件下载)
application/x-www-form-urlencoded : 中默认的 encType,form 表单数据被编码为 key/value 格式发送到服务器(表单默认的提交数据的格式)
b. content-type 实例说明
上面算是基本定义和取值,下面结合实例对典型的几种方式进行说明
application/x-www-form-urlencoded:数据被编码为名称/值对。这是标准的编码格式。
multipart/form-data: 数据被编码为一条消息,页上的每个控件对应消息中的一个部分。
text/plain: 数据以纯文本形式(text/json/xml/html)进行编码,其中不含任何控件或格式字符
对于前端使用而言,form 表单的 enctype 属性为编码方式,常用有两种:application/x-www-form-urlencoded 和 multipart/form-data,默认为 application/x-www-form-urlencoded。
Get 请求
发起 Get 请求时,浏览器用 application/x-www-form-urlencoded 方式,将表单数据转换成一个字符串(key1=value1&key2=value2...)拼接到 url 上,这就是我们常见的 url 带请求参数的情况
Post 表单
发起 post 请求时,如果没有传文件,浏览器也是将 form 表单的数据封装成 k=v 的结果丢到 http body 中,拿开源中国的博客提交的表单为例,一个典型的 post 表单,上传的数据拼装在 form data 中,为 kv 结构
如果有传文件的场景,Content-Type 类型会升级为 multipart/form-data,这一块不详细展开,后面有机会再说
Post json 串
post 表单除了前面一种方式之外,还有一种也是我们常见的,就是将所有的表单数据放在一个大的 json 串中,然后丢给后端,这里也有一个在线的实例,某电商平台的商品发表,截图如下
注意看上面的 Request Payload,是一个大的 json 串,和前面差别明显
c. RequestBody 请求
根据 RequestBody 的定义,要想访问前面定义的那个接口,使用传统的表单传递方式是不行的,curl 命令测试如下
后端对应的输出如下(抛了一个异常,表示 @RequestBody 注解修饰 rest 接口,不支持 Content type 'application/x-www-form-urlencoded;charset=UTF-8'
因此使用姿势需要显示添加请求头,传参也改变一下
返回结果如下
3. 注意事项
a. content-type 显示指定
根据前面的说明,可以知道 @RequestBody 这个注解的使用,使得 REST 接口接收的不再 content-type 为 application/x-www-form-urlencoded 的请求, 反而需要显示指定为 application/json
b. 请求方法
RequestBody 支持 GET 方法么?前面都是采用 post 提交参数,如果改成 GET 会怎样?
curl 测试方式
对应的后端 debug 截图如下,发现使用 GET 方式,并没有问题,依然可以获取到参数
换成大名鼎鼎的 POSTMAN 来测试
使用 post 方法请求时,截图如下,主要就是修改 header 的 content-type,然后在 body 中添加 json 串格式的请求
然而改成 get 之后,body 都直接灰掉了,也就是它不支持在 get 请求时,提交 Body 数据
url 请求方式
接下来直接换成 url 的请求方式,看是否直接支持 get 请求
浏览器中输入时,服务器 400, 换成 curl 方式请求,抛的是缺少 RequestBody 的异常,也就是说,将 json 串拼接到 url 中貌似不行(也有可能是我的使用姿势不对。。。)
小结
到这里小结一下,使用 RequestBody 获取参数时,还是老老实实地选择 POST 方法比较合适,至于原因,跟大众,随主流,跟着大家的习惯走比较好
c. 参数获取
这个主要就是后端编写接口时,获取 RequestBody 参数的问题了,通过测试,发现在 HttpServletRequest 参数中,居然拿不到提交的 RequestBody 参数,演示如下
请求 url 为
对应的 debug 截图如下,url 参数可以拿到,RequestBody 参数没有
首先声明,下面的这段分析,没有看源码,纯属于个人推断,如有问题,对被误导的朋友表示歉意,也希望对此有了解的朋友,多多批评指正
对上面的猜测做一个小小的验证,改成直接从 HttpServletRequest 的 Reader 流中获取请求 body 参数
验证如下
其实到这里,有个有意思的地方已经引起了我的好奇,那就是在 Spring 容器中 HttpServletRequest 这个东西,是怎么运转的,后面有机会再聊,此处不展开...
4. 小结
ReuqestBody 主要是处理 json 串格式的请求参数,要求使用方指定 header content-type:application/json
RequestBody 通常要求调用方使用 post 请求
RequsetBody 参数,不会放在 HttpServletRequest 的 Map 中,因此没法通过 javax.servlet.ServletRequest#getParameter 获取
原文链接:https://juejin.cn/post/6844903648858734600
版权声明: 本文为 InfoQ 作者【学Java关注我】的原创文章。
原文链接:【http://xie.infoq.cn/article/951554802f4a6805c3b72fa81】。文章转载请联系作者。
评论