目标
了解http常见的mime类型定义;
如何使用springboot 处理json请求及响应;
如何使用springboot 处理 xml请求及响应;
http参数的获取及文件上传下载;
如何获得原始请求的字节流; 6.了解springboot 如何实现内容转换;
一、关于MIME
MIME的全称是Multipurpose Internet Mail Extensions,即多用途互联网邮件扩展,尽管读起来有些拗口,但大多数人可能都知道,这是HTTP协议中用来定义文档性质及格式的标准。IETF RFC 6838,对HTTP传输内容类型进行了全面定义。而IANA(互联网号码分配机构)是负责管理所有标准MIME类型的官方机构。可以在这里)找到所有的标准MIME
服务器通过MIME告知响应内容类型,而浏览器则通过MIME类型来确定如何处理文档;因此为传输内容(文档、图片等)设置正确的MIME非常重要。通常Server会在HTTP响应中设置Content-Type,如下面的响应:
这表示服务端将返回html格式的文档,而同样客户端也可以在HTTP请求中设置Content-Type以告知服务器当前所发送内容的格式。
如下面的请求体:
这表示客户端会发送application/json格式的数据到服务端,同时应该注意到Accept请求头,这个选项用于告知服务器应该返回什么样的数据格式(由客户端接收并完成解析)。
MIME的格式
这是一个两级的分类,比较容易理解,第一级分类通常包含:
而二级类型则非常多,以下是一些常用的MIME:
接下来,看看springboot如何实现几个常见类型格式的处理。
二、springboot-json处理
先看看这样一段代码:
这是一个Controller层的方法定义,其中@PostMapping将该方法映射到/json路径的POST方法。
consumes = { MediaType.APPLICATIONJSONUTF8_VALUE } 指定了该方法仅处理application/json的内容格式
produces="application/json;charset=UTF-8" 则表示会在响应头中指定Content-Type=application/json;charset=UTF-8
@RequestBody 指定了将请求的输入通过Json转换为DTO
@ResponseBody 指定将响应对象转换为Json格式输出
通过观察请求响应,我们会得到以下的结果:
使用Postman工具进行调试,可以非常直观的获得想要的信息,点击这里可以下载
异常情况
如果,请求的内容格式不是json,而是其他的如application/x-www-form-urlencoded呢?放心,框架会返回如下面的错误:
三、springboot-xml处理
如上,通过springboot框架,我们快速实现了Json格式的输入输出。那么,如何实现xml格式的处理呢?xml格式主要用于soap、rpc等领域,为了实现xml数据的序列化,我们需要添加jackson-xml依赖包
接下来,声明一个Controller方法
这次,我们指定了consumes、produces都是application/xml,通过@RequestBody、@ResponseBody注解之后,springboot框架会自动根据需求的内容格式进行转换。
这里的ParamData是一个简单的Pojo类:
通过真实的请求-响应观测,我们得到如下的结果:
BTW,springboot 完成自动类型转换是通过内容协商实现的,相关的接口为ContentNegotiationManager。默认情况下,对于声明了consumes及produce属性的方法,会按照声明的值进行处理,否则格式的转换会根据请求中的Content-Type、Accept头部来进行判断。
此外,实现请求/响应内容到DTO转换功能的是HttpMessageConverter接口。
准确说,内容转换是由springmvc框架提供,而springboot是一个整合模块的脚手架
四、http参数处理
对于普通的表单请求参数处理,我们通常有两种方式:
通过方法参数映射
通过参数绑定
form表单的请求内容格式为application/x-www-form-urlencoded,
一个请求的样例如下:
五、文件上传下载
对于文件上传,我们需要将请求声明为multipart/form-data格式,一个文件上传的请求样例如下:
参照以下的代码可以实现简单的文件上传处理:
这个例子非常简单,通过声明@RequestParam注解获得MultipartFile对象,在获得上传文件后存储到服务器本地目录。当然,在真实的项目应用中你需要做的更多,比如文件的大小、类型校验,将文件进行压缩或将文件存放到大容量、高稳定性的分布式文件存储系统等等。
这里不多啰嗦了,关于文件下载,可以通过以下的方法实现:
聪明的读者一定会发现,除了将文件内容作为输出之外,我们还为响应添加两个header:
Content-Type:application/octet-stream,这表示响应的文档是未知的二进制数据,大多数情况下浏览器会直接下载;
Content-Disposition →attachment;fileName=test.jpg,表示文档应该作为附件保存,并名称为test.jpg。
六、获得原始字节流
在某些情况下,你可能需要获得原始的请求字节流,比如实现内容的过滤,或者为了完成制作自己的RPC接口。在springboot中获得字节流非常简单,从Servlet API的定义中可以发现,直接通过HttpServletRequest对象便可以获取一个InputStream。
在我们定义的Controller方法中,还可以直接声明流类型的参数以获取数据。
然而,如果这么做了,你可能会遇到一些麻烦:当请求头中Content-Type=application/x-www-form-urlencoded时,你会获得一个空的InputStream!
笔者曾经在制作代理服务器的时候遇到了这个问题,经过一番查阅,发现问题的原因在于:
按照Servlet规范,如果同时满足下列条件,则请求体(Entity)中的表单数据,将被填充到request的parameter集合中(导致inputstream为空)。1 这是一个HTTP/HTTPS请求2 请求方法是POST3 请求的类型Content-Type=application/x-www-form-urlencoded4 Servlet调用了getParameter系列方法
springboot框架内置了HiddenHttpMethodFilter,用于支持浏览器form表单无法支持put/delete等请求方法的问题。在Filter的实现中发现存在如下代码:
由于getParameter被提前调用,导致后续获取InputStream为空。该问题的解决方法是实现HttpServletRequest的代理,事先将InputStream保存起来供多次使用,通过高优先级的过滤器提前将Request对象置换可达到目的。由于篇幅限制这里不做展开。感兴趣的可以参考这里获得更多信息。
小结
HTTP协议中定义了MIME标准,以实现传输内容格式的识别及转换。本文介绍了常见的MIME类型,并结合springboot框架的代码样例,讲述如何完成Json/xml/字节流等常见类型的内容处理。
对于Http参数、文件的上传下载提供了简单代码示例,读者在充分了解用法之后可以进一步完善,并应用到实际的项目中去。
领取专属 10元无门槛券
私享最新 技术干货