做web开发的前后端同学对于postman这个工具一定不会陌生。在图示位置中,Body里我们可以看到有几个选项,其中常用的有form-data,x-www-form-urlencoded,raw,binary,它们具体对应的分别是multipart/form-data,application/x-www-from-urlencoded,text/plain,application/octet-stream这四种模式。
首先multipart/form-data是用以支持向服务器发送二进制数据的一种文本类型。1995年,ietf 出台了 rfc1867,也就是《RFC 1867 -Form-based File Upload in HTML》,用以支持文件上传。它是HTML表单中的enctype类型之一(其它还包括application/x-www-from-urlencoded,text/plain),即表单数据编码的一种方式。
使用这种方式上传上传数据时,必须先要定义一个boundary,用于隔离不同的键值对,而这个键值对的值可以是文本,也可以是文件。这在实际使用中比单纯地上传文本或者只能上传一个文件(如:Content-Type:application/octet-stream)的模式要方便很多。如图所示,postman中采用了form-data,设置了一个文本的key1以及一个文件的key2,可以看右侧HTTP报文的内容:
不同的框架对于这个类型的处理也是做了很好地支持。如Java中各种框架中Multipart打头的类基本都是处理这种相关内容的。理解了multipart/form-data,其实也就可以很好地理解application/x-www-from-urlencoded和application/octet-stream这两种类型了。下面这张图展示了选择application/x-www-from-urlencoded时(注意中文的处理):
可以看到,参数这里已经通过URLEncode进行了转码,在参数配置栏中也可以看到VALUE栏下只能填写纯文本,无法选择文件。再看binary这种方式,可以看到它里面没有KEY-VALUE输入框,有一个Select File选项,并且只有一个。所以这里就能看出来multipart和binary,x-www-form-urlencoded之间的区别与联系。大家可以在一个SpringBoot(或者SpringMVC)的Controller中,在response里填写如下内容,然后看看从浏览器访问这个接口时会发生什么:
...
String rfc5987FileName = RFC5987StringUtils.rfc5987_encode(fileName);
response.setContentType("application/octet-stream");
response.setHeader("Content-Disposition", "attachment;filename="" + rfc5987FileName + "";filename*=utf-8''" + rfc5987FileName);
并从中体会application/octet-stream的用法。
另外,raw对应的是Content-Type中的纯文本,text/plain,如图所示:
-------------------------------------------------------------------------------------
可以发现,postman的Body下这几个选项其实都跟http协议中的Content-Type有关,那么我们在此也对这个内容做个扩展。
Content-Type表示媒体类型信息,有了这个信息,服务器和客户端的浏览器就能够更好地进行内容适配。这里给出一个详细的media types说明地址:https://www.iana.org/assignments/media-types/media-types.xhtml
其中常见的格式有:
application/json,application/x-www-form-urlencoded,multipart/form-data,application/octet-stream,text/plain...
postman中把这些内容基本上都覆盖了。
这个协议中,“/”之前的内容表示主协议,之后的内容表示子协议,经常还会在这之后加上参数如charset。类型的格式如下:
格式:type/subtype(;parameter)?type
示例:Content-Type:text/html;charset:utf-8;
-------------------------------------------------------------------------------------
另外,在SpringBoot/SpringMVC中,@RequestMapping中几个重要的属性,这里说明一下:
- String[] value/path: 这俩是相同的,也很好理解,表示路径;
- String name: 自定义一个name属性,官方说明可以通过使用Spring jsp tag包里面的mvcUrl,来生成jsp到Controller的链接(默认是类大写字符+#+方法名来构建的)。
@Controller
@ResponseBody
@RequestMapping(name = "AdminController")
class BlogController {
@RequestMapping(name="BlogComments", path="blog/{blog}/comments/{page}")
public List<Comment> listBlogComments(@PathVariable Blog blog, @PathVariable Long page) {
...
}
}
在JSP中,可以通过如下方式获取到URL:
<%@ taglib uri="http://www.springframework.org/tags" prefix="s" %>
<a href="${s:mvcUrl('AdminController#BlogComments').arg("1","123").build()}">Get Person</a>
- RequestMethod[] method: 如果不进行设置,默认是支持所有类型的RequestMethod。
- String[] params: 筛选params,只有满足了条件的key/value出现,才会执行这个方法。可以使用key=value判断,也可以使用key!=value的形式来判断。这个在类型和方法级别都是支持的。
- String[] headers: 筛选headers,只有满足了条件的key/value出现,才会执行这个方法。可以使用key=value判断,也可以使用key!=value的形式来判断,甚至支持通配符*。这个在类型和方法级别都是支持的。
RequestMapping(value = "/something", headers = "content-type=text/*")
此时只有满足headers条件的请求才会被正确执行。
- String[] consumes: 针对Content-Type进行请求过滤。必须满足这里设置的过滤条件,这个请求才会被执行。如:
consumes="text/plain"
consumes={"text/plain","application/*"}
consumes="!text/plain"
- String[] produces: 针对Accept进行请求过滤。必须满足条件,这个请求才会被执行。如:
produces="text/plain"
produces={"text/plain","application/*"}
produces="!text/plain"