form-data、x-www-form-urlencoded、raw的区别

a 夏天 提交于 2019-12-04 15:04:08

http请求 
场景: 
前端:SDK通过http发送请求/页面Ajax提交。 
后台:Springboot服务,Rest风格,需在controller层之前拦截请求。

Springboot支持Rest风格给编码带来了很好的便捷性,@RequestBody让我们可以直接以application/json请求并在到达controller层获得已反序列化的对象,当有拦截的需求,这种方式却不再奏效。

application/x-www-form-urlencoded通过表单提交,在sevlet实现中,mutipart/form-data和application/x-www-form-urlencoded会被特殊处理,请求参数将被放置于request.paramter,这是一个map。我们可以从map中获取参数进行验证,或者其他拦截需求,map的获取类似hibernate的延迟加载,当调用request.getparamter()方法,servlet才会从请求流中读取请求参数加载入map。InputStream也会存有这份数据,但如果这份数据被读取,那么到了controller层将无法读出数据,同样,拦截之后到达controller层时请求数据已经被加载入了controller层方法实参,实参对象需要有set方法,框架会以反射的方式调用属性的set方法注入数据,数据只会被注入到已有的属性。

当以application/json的content-type传送数据,被传送的对象只需被json序列化。当以application/x-www-form-urlencoded的方式传送数据。请求的内容需要以..=..&..=..的格式提交,在请求体内内容将会以”&”和“ = ”进行拆分。

    app.controller('mailController', function($scope, $http) {
            $scope.guest = {};
            $scope.authError = null;
            $scope.send = function() {
                var req = {
                    method:'POST',
                    url:'/mail/send',
                    headers: {
                        'Accept':'application/json',
                        'Content-Type':'application/x-www-form-urlencoded'
                    },
                    data:"from=" + $scope.guest.from + '&' + "subject=" + $scope.guest.subject + '&' + "content=" + $scope.guest.content
                };

Fiddler: 
这里写图片描述

将提交数据格式改一下:

data:$scope.guest.serialize()

Fiddler: 
这里写图片描述

request.paramter中将以 
key:{“from”:”awtrmml91@163.com”,”subject”:”主题”,”content”:”正文”} 
value:”” 
的形式出现。

后台将无法读取提交数据,这种情况下json数据解析正常: 

这里写图片描述 
但你需要使用content-type=application/json且后台使用@RequestBody,你无法再从paramter中获取请求数据。

选择application/x-www-form-urlencoded还是application/json,得看你是否有从request.paramter获取请求数据的需求。

区别

form-data方式

  • 表示http请求中的multipart/form-data方式,会将表单的数据处理为一条消息,用分割符隔开,可以上传键值对或者上传文件:

    1、对于一段utf8编码的字节,用application/x-www-form-urlencoded传输其中的ascii字符没有问题,但对于非ascii字符传输效率就很低了(汉字‘丁’从三字节变成了九字节),因此在传很长的字节(如文件)时应用multipart/form-data格式。smtp等协议也使用或借鉴了此格式。

    2、此格式表面上发送了什么呢。用此格式发送一段一句话和一个文件,请求体如下:

  • 同时请求头里规定了Content-Type: multipart/form-data; boundary=----WebKitFormBoundarymNhhHqUh0p0gfFa8

    可见请求体里不同的input之间用一段叫boundary的字符串分割,每个input都有了自己一个小header,其后空行接着是数据。

    3、此格式实际上发送了什么呢。fiddler抓包如下

  • 右边明显看到了一段乱码,为什么呢,以汉字‘丁’为例,其utf8编码为0xE4B881,这三个字节会直接拼接到数据包中,即其在实际发送时只占三字节,上图右边是逐字节转为ascii字符显示的,因此会显示为三个乱码字符。由上可见,multipart/form-data将表单中的每个input转为了一个由boundary分割的小格式,没有转码,直接将utf8字节拼接到请求体中,在本地有多少字节实际就发送多少字节,极大提高了效率,适合传输长字节。

  • application/x-www-form-urlencoded

  • 1、它是post的默认格式,使用js中URLencode转码方法。包括将name、value中的空格替换为加号;将非ascii字符做百分号编码;将input的name、value用‘=’连接,不同的input之间用‘&’连接。

    2、百分号编码什么意思呢。比如汉字‘丁’吧,他的utf8编码在十六进制下是0xE4B881,占3个字节,把它转成字符串‘E4B881’,变成了六个字节,每两个字节前加上百分号前缀,得到字符串“%E4%B8%81”,变成九个ascii字符,占九个字节(十六进制下是0x244534254238253831)。把这九个字节拼接到数据包里,这样就可以传输“非ascii字符的  utf8编码的 十六进制表示的 字符串的 百分号形式”,^_^。

    3、同样使用URLencode转码,这种post格式跟get的区别在于,get把转换、拼接完的字符串用‘?’直接与表单的action连接作为URL使用,所以请求体里没有数据;而post把转换、拼接后的字符串放在了请求体里,不会在浏览器的地址栏显示,因而更安全一些。

  • name=wangjianfeng&age=12

    multipart/form-data与x-www-form-urlencoded的区别 

  • multipart/form-data:可以上传文件或者键值对,最后都会转化为一条消息
  • x-www-form-urlencoded:只能上传键值对,而且键值对都是通过&间隔分开的。
  • raw

  • 可以上传任意格式的文本,文本不做任何修饰传到服务端。比如传一些xml,或者json数据,或者text文本数据。
标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!