定义和用法
enctype 属性规定在发送到服务器之前应该如何对表单数据进行编码。
默认地,表单数据会编码为 “application/x-www-form-urlencoded”。就是说,在发送到服务器之前,所有字符都会进行编码(空格转换为 “+” 加号,特殊符号转换为 ASCII HEX 值)。
enctype属性值
值 | 描述 |
---|---|
application/x-www-form-urlencoded | 在发送前编码所有字符(默认) |
multipart/form-data |
不对字符编码。 在使用包含文件上传控件的表单时,必须使用该值。 |
text/plain | 空格转换为 “+” 加号,但不对特殊字符编码。 |
HTTP/1.1 协议规定的 HTTP 请求方法有 OPTIONS、GET、HEAD、POST、PUT、DELETE、TRACE、CONNECT 这几种。
其中 POST 一般用来向服务端提交数据,本文主要讨论 POST 提交数据的几种方式。
我们知道,HTTP 协议是以 ASCII 码传输,建立在 TCP/IP 协议之上的应用层规范。
规范把 HTTP 请求分为三个部分:状态行、请求头、消息主体。类似于下面这样:
BASH<method> <request-URL> <version>
<headers>
<entity-body>
协议规定 POST 提交的数据必须放在消息主体(entity-body)中,但协议并没有规定数据必须使用什么编码方式。实际上,开发者完全可以自己决定消息主体的格式,只要最后发送的 HTTP 请求满足上面的格式就可以。
但是,数据发送出去,还要服务端解析成功才有意义。一般服务端语言如 php、python 等,以及它们的 framework,都内置了自动解析常见数据格式的功能。
服务端通常是根据请求头(headers)中的 Content-Type 字段来获知请求中的消息主体是用何种方式编码,再对主体进行解析。
所以说到 POST 提交数据方案,包含了 Content-Type 和消息主体编码方式两部分。
下面就正式开始介绍它们。
application/x-www-form-urlencoded
这应该是最常见的 POST 提交数据的方式了。浏览器的原生 <form> 表单,如果不设置 enctype
属性,那么最终就会以 application/x-www-form-urlencoded 方式提交数据。
<form action="form_action.asp" enctype="text/plain"> <p>First name: <input type="text" name="fname" /></p> <p>Last name: <input type="text" name="lname" /></p> <input type="submit" value="Submit" /> </form>
此时Form提交的请求数据,抓包时看到的请求会是这样的内容(无关的请求头在本文中都省略掉了):
BASHPOST
h
ttp://www.example.com
HTTP/1.1
Content-Type: application/x-www-form-urlencoded;charset=utf-8
title=test&sub%5B%5D=1&sub%5B%5D=2&sub%5B%5D=3
首先,Content-Type 被指定为 application/x-www-form-urlencoded;其次,提交的数据按照 key1=val1&key2=val2 的方式进行编码,key 和 val 都进行了 URL 转码。
大部分服务端语言都对这种方式有很好的支持。例如 PHP 中,$_POST[‘title’] 可以获取到 title 的值,$_POST[‘sub’] 可以得到 sub 数组。
很多时候,我们用 Ajax 提交数据时,也是使用这种方式。
例如 JQuery 和 QWrap 的 Ajax,Content-Type 默认值都是「application/x-www-form-urlencoded;charset=utf-8」。
multipart/form-data
这又是一个常见的 POST 数据提交的方式。我们使用表单上传文件时,必须让 <form> 表单的enctype 等于 multipart/form-data。直接来看一个请求示例:
BASHPOST http://www.example.com HTTP/1.1
Content-Type:multipart/form-data; boundary=----WebKitFormBoundaryrGKCBY7qhFd3TrwA
------WebKitFormBoundaryrGKCBY7qhFd3TrwA
Content-Disposition: form-data; name="text"
title
------WebKitFormBoundaryrGKCBY7qhFd3TrwA
Content-Disposition: form-data; name="file"; filename="chrome.png"
Content-Type: image/png
PNG ... content of chrome.png ...
------WebKitFormBoundaryrGKCBY7qhFd3TrwA--
这个例子稍微复杂点。首先生成了一个 boundary 用于分割不同的字段,为了避免与正文内容重复,boundary 很长很复杂。然后 Content-Type 里指明了数据是以 multipart/form-data 来编码,本次请求的 boundary 是什么内容。消息主体里按照字段个数又分为多个结构类似的部分,每部分都是以 --boundary
开始,紧接着是内容描述信息,然后是回车,最后是字段具体内容(文本或二进制)。如果传输的是文件,还要包含文件名和文件类型信息。消息主体最后以 --boundary--
标示结束。
关于 multipart/form-data 的详细定义,请前往 rfc1867 查看。
这种方式一般用来上传文件,各大服务端语言对它也有着良好的支持。
上面提到的这两种 POST 数据的方式,都是浏览器原生支持的,而且现阶段标准中原生 <form> 表单也只支持这两种方式(通过 <form> 元素的 enctype
属性指定,默认为 application/x-www-form-urlencoded
。其实 enctype
还支持 text/plain
,不过用得非常少)。
随着越来越多的 Web 站点,尤其是 WebApp,全部使用 Ajax 进行数据交互之后,我们完全可以定义新的数据提交方式,给开发带来更多便利。
application/json
application/json 这个 Content-Type 作为响应头大家肯定不陌生。实际上,现在越来越多的人把它作为请求头,用来告诉服务端消息主体是序列化后的 JSON 字符串。由于 JSON 规范的流行,除了低版本 IE 之外的各大浏览器都原生支持 JSON.stringify,服务端语言也都有处理 JSON 的函数,使用 JSON 不会遇上什么麻烦。
JSON 格式支持比键值对复杂得多的结构化数据,这一点也很有用。记得我几年前做一个项目时,需要提交的数据层次非常深,我就是把数据 JSON 序列化之后来提交的。不过当时我是把 JSON 字符串作为 val,仍然放在键值对里,以 x-www-form-urlencoded 方式提交。
Google 的 AngularJS 中的 Ajax 功能,默认就是提交 JSON 字符串。例如下面这段代码:
JSvar data = {'title':'test', 'sub' : [1,2,3]}; $http.post(url, data).success(function(result) { ... });
最终发送的请求是:
BASHPOST http://www.example.com HTTP/1.1 Content-Type: application/json;charset=utf-8 {"title":"test","sub":[1,2,3]}
这种方案,可以方便的提交复杂的结构化数据,特别适合 RESTful 的接口。各大抓包工具如 Chrome 自带的开发者工具、Firebug、Fiddler,都会以树形结构展示 JSON 数据,非常友好。但也有些服务端语言还没有支持这种方式,例如 php 就无法通过 $_POST 对象从上面的请求中获得内容。这时候,需要自己动手处理下:在请求头中 Content-Type 为 application/json 时,从 php://input
里获得原始输入流,再 json_decode
成对象。一些 php 框架已经开始这么做了。
当然 AngularJS 也可以配置为使用 x-www-form-urlencoded 方式提交数据。如有需要,可以参考这篇文章。
text/xml
我的博客之前提到过 XML-RPC(XML Remote Procedure Call)。它是一种使用 HTTP 作为传输协议,XML 作为编码方式的远程调用规范。典型的 XML-RPC 请求是这样的:
HTMLPOST http://www.example.com HTTP/1.1 Content-Type: text/xml <?xml version="1.0"?> <methodCall> <methodName>examples.getStateName</methodName> <params> <param> <value><i4>41</i4></value> </param> </params> </methodCall>
XML-RPC 协议简单、功能够用,各种语言的实现都有。它的使用也很广泛,如 WordPress 的 XML-RPC Api,搜索引擎的 ping 服务等等。JavaScript 中,也有现成的库支持以这种方式进行数据交互,能很好的支持已有的 XML-RPC 服务。不过,我个人觉得 XML 结构还是过于臃肿,一般场景用 JSON 会更灵活方便。
https://imququ.com/post/four-ways-to-post-data-in-http.html
rest api参数与content-type
最近为项目组提供rest api 时遇到了关于接口参数的传递问题,主要是没有充分考虑到第三方调用者的使用方式,应该尽量的去兼容公司之前提供出去的接口调用方式,这样可以降低第三方调用者的学习成本,尽管之前的方式并不是那么的推荐,好的做法是即兼容老的做法也支持推荐的做法。
对于基于http post接口,Content-type我会优先选择application/json,但公司之前提供的接口恰恰采用了application/x-www-form-urlencoded,它是表单默认的提交类型,基于key/value形式提交到服务端的。
spring mvc是如何接收下面两种经典数据的? (至于form-data,它即可以传键值对也可以上传文件,这里不涉及到文件所以只讨论下面两种):
Content-type=application/json:需要在参数上增加@RequestBody这个注解,说明参数是从http的requestbody中获取。
下图中的参数,是标准的json格式,对前端js非常友好。
Content-type=application/x-www-form-urlencoded,参数上不能增加@RequestBody的注解
下图的可以看出参数形式与get请求时,URL后面的参数格式
为什么不推荐采用application/x-www-form-urlencoded这种类型,它有如下问题:
测试困难,就别想通过postman这类工具测试:提交到服务端实际上是一个MultiValueMap(org.springframework.util.MultiValueMap或org.springframework.util.LinkedMultiValueMap),
如果value中的对象也是一个对象,那么在构建这个参数时就非常困难,看下它的过程
采用key1=value1&key2=value2这种形式将所有参数拼接起来,从一长串字符中想了解每个参数的含义没有个好眼力怕是不行。
value要进行编码,编码之后的对调试者不友好。
value是复杂对象的情况更加糟糕,一般只能通过程序来序列化得到参数,想手写基本不可能。
客户端调用复杂
新版本Postman在此处查看:
2、x-www-form-urlencoded:
就是application/x-www-from-urlencoded,会将表单内的数据转换为键值对,比如,name=java&age = 23
3、raw
可以上传任意格式的文本,可以上传text、json、xml、html等
4、binary
相当于Content-Type:application/octet-stream,从字面意思得知,只可以上传二进制数据,通常用来上传文件,由于没有键值,所以,一次只能上传一个文件。
multipart/form-data与x-www-form-urlencoded区别
multipart/form-data:既可以上传文件等二进制数据,也可以上传表单键值对,只是最后会转化为一条信息;
x-www-form-urlencoded:只能上传键值对,并且键值对都是间隔分开的。
http://blog.csdn.net/ye1992/article/details/49998511
上传文件的表单中<form>要加属性enctype=”multipart/form-data”,很多人只是死记硬背知道上传表单要这么 写,知其然而不知其所以然。那到底为什么要添加这个属性呢?它是什么意思呢?它又有什么其他可选值呢? 其实form表单在你不写enctype属性时,也默认为其添加了enctype属性值,默认值是enctype=”application/x- www-form-urlencoded”.这个属性管理的是表单的MIME编码,共有三个值可选:
①application/x-www-form-urlencoded (默认值)
②multipart/form-data
③text/plain
其中①application/x-www-form-urlencoded是默认值,大家可能在AJAX里见过这 个:xmlHttp.setRequestHeader(“Content-Type”,”application/x-www-form- urlencoded”); 这两个要做的是同一件事情,就是设置表单传输的编码。在AJAX里不写有可能会报错,但是在HTML的form表单里是可以不写 enctype=”application/x-www-form-urlencoded”的,因为默认HTML表单就是这种传输编码类型。而 ②multipart-form-data是用来指定传输数据的特殊类型的,主要就是我们上传的非文本的内容,比如图片或者mp3等等。 ③text/plain是纯文本传输的意思,在发送邮件时要设置这种编码类型,否则会出现接收时编码混乱的问题,网络上经常拿text/plain和 text/html做比较,其实这两个很好区分,前者用来传输纯文本文件,后者则是传递html代码的编码类型,在发送头文件时才用得上。①和③都不能用 于上传文件,只有multipart/form-data才能完整的传递文件数据。
上面提到的MIME,它的英文全称是”Multipurpose Internet Mail Extensions” 多功能Internet 邮件扩充服务,它是一种多用途网际邮件扩充协议,在1992年最早应用于电子邮件系统,但后来也应用到浏览器。服务器会将它们发送的多媒体数据的类型告诉 浏览器,而通知手段就是说明该多媒体数据的MIME类型,从而让浏览器知道接收到的信息哪些是MP3文件,哪些是Shockwave文件等等。服务器将 MIME标志符放入传送的数据中来告诉浏览器使用哪种插件读取相关文件。
简单说,MIME类型就是设定某种扩展名的文件用一种应用程序来打开的方式类型,当该扩展名文件被访问的时候,浏览器会自动使用指定应用程序来打开。多用于指定一些客户端自定义的文件名,以及一些媒体文件打开方式。
浏览器接收到文件后,会进入插件系统进行查找,查找出哪种插件可以识别读取接收到的文件。如果浏览器不清楚调用哪种插件系统,它可能会告诉用户缺少某 插件,或者直接选择某现有插件来试图读取接收到的文件,后者可能会导致系统的崩溃。传输的信息中缺少MIME标识可能导致的情况很难估计,因为某些计算机 系统可能不会出现什么故障,但某些计算机可能就会因此而崩溃。
检查一个服务器是否正确设置了MIME类型的步骤是:
1. 在Netscape浏览器中打开服务器网页
2. 进入”View”菜单,选择”Page Info”
3. 在弹出的窗口中点击上层框架中的”EMBED”
4. 在下层框架中查看MIME的类型是否为”application/x-director”或”application/x-shockwave- flash”,如果是上述信息的话表明服务器已经正确设置了MIME类型;
而如果MIME类型列出的是文本内容、八位一组的数据或是其它形式均表明服务器 的MIME类型没有设置正确。
如果服务器没有正确标明其发送的数据的类型,服务器管理员应该正确添加相关信息,具体操作方法非常简单快捷。
每个MIME类型由两部分组成,前面是数据的大类别,例如声音audio、图象image等,后面定义具体的种类。
常见的MIME类型
超文本标记语言文本 .html,.html text/html
普通文本 .txt text/plain
RTF文本 .rtf application/rtf
GIF图形 .gif image/gif
JPEG图形 .jpeg,.jpg image/jpeg
au声音文件 .au audio/basic
MIDI音乐文件 mid,.midi audio/midi,audio/x-midi
RealAudio音乐文件 .ra, .ram audio/x-pn-realaudio
MPEG文件 .mpg,.mpeg video/mpeg
AVI文件 .avi video/x-msvideo
GZIP文件 .gz application/x-gzip
TAR文件 .tar application/x-tar
Internet中有一个专门组织IANA来确认标准的MIME类型,但Internet发展的太快,很多应用程序等不及IANA来确认他们使用 的MIME类型为标准类型。因此他们使用在类别中以x-开头的方法标识这个类别还没有成为标准,例如:x-gzip,x-tar等。事实上这些类型运用的 很广泛,已经成为了事实标准。只要客户机和服务器共同承认这个MIME类型,即使它是不标准的类型也没有关系,客户程序就能根据MIME类型,采用具体的 处理手段来处理数据。而Web服务器和浏览器(包括操作系统)中,缺省都设置了标准的和常见的MIME类型,只有对于不常见的 MIME类型,才需要同时设置服务器和客户浏览器,以进行识别。
—————————————————————-
表单中enctype=”multipart/form-data”的意思,是设置表单的MIME编码。默认情况,
这个编码格式是application/x-www-form-urlencoded,不能用于文件上传;
只有使用了multipart/form-data,才能完整的传递文件数据,进行下面的操作.
enctype=”multipart/form-data”是上传二进制数据; form里面的input的值以2进制的方式传过去。
form里面的input的值以2进制的方式传过去,
所以request就得不到值了。也就是说加了这段代码,用request就会传递不成功,取表单值加入数据库时,用到下面的:
SmartUpload su = new SmartUpload();//新建一个SmartUpload对象 su.getRequest().getParameterValues();取数组值 su.getRequest().getParameter( );取单个参数单个值
ajax中的application/x-www-form-urlencoded中的使用
一,HTTP上传的基本知识
在Form元素的语法中,EncType表明提交数据的格式 用 Enctype 属性指定将数据回发到服务器时浏览器使用的编码类型。下边是说明: application/x-www-form-urlencoded: 窗体数据被编码为名称/值对。这是标准的编码格式。 multipart/form-data: 窗体数据被编码为一条消息,页上的每个控件对应消息中的一个部分。 text/plain:窗体数据以纯文本形式进行编码,其中不含任何控件或格式字符。
补充
form的enctype属性为编码方式,常用有两种:application/x-www-form-urlencoded和multipart/form-data,默认为application /x-www-form-urlencoded。
当action为get时候,浏览器用x-www-form-urlencoded的编码方式把form数据转换成一个字串(name1=value1& amp; amp;name2=value2…),然后把这个字串append到url后面,用?分割,加载这个新的url。
当action为post时候,浏览器把form数据封装到http body中,然后发送到server。
如果没有type=file的控件,用默认的application/x-www-form-urlencoded就可以了。但是如果有 type=file的话,就要用到multipart/form-data了。
浏览器会把整个表单以控件为单位分割,并为每个部分加上 Content-Disposition(form-data或者file),Content-Type(默认为text/plain),name(控件 name)等信息,并加上分割符(boundary)。
二,使用中需要注意的地方
在AJAX往服务器上传数据是,设置了content-type为application/x-www-form-urlencoded,此时是对整个发 送内容作了编码,并不是对名字对应的值做了编码。因此,在服务器端,通过request.getParameter(“name”)的方式取值,是有问题 的。
有两种解法办法:
1)改服务器端: 采用流的方式硬编码
InputStream stream=request.getInputStream(); InputStreamReader isr=new InputStreamReader(stream); BufferedReader br=new BufferedReader(isr); String str=br.readLine(); System.out.println(str); str=URLDecoder.decode(str,"gb2312"); System.out.println(str); br.close();
2)改客户端:更改数据发送结构
在往服务器上发数据的时候,使用name=escape(value)的方式组对
此时在服务器代码中,通过request.getParameter(“name”)获得的数值,就不用编码了
application/x-www-form-urlencoded、multipart/form-data、text/plain
http://www.cnblogs.com/mumue/archive/2012/05/24/2515984.html
org.springframework.web.HttpMediaTypeNotSupportedException: Content type ‘multipart/form-data;boundary=—-WebKitFormBoundaryRAYPKeHKTYSNdzc1;charset=UTF-8‘ not supported
最近同事在做一个图片上传功能、在入参 body 中同时传入文件和其它基本信息结果出现如题异常、在此记录下解决办法、以做记录。
controller 代码如下:
@RequestMapping(value = "/upload", method =RequestMethod.POST) @ResponseBody public String upload(@RequestParam("file") MultipartFile file, @RequestBody User user) { // 业务处理 ...... ...... }
在使用工具测试(Postman、 swagger )时报如下异常
"timestamp": 1473349676109, "status": 415, "error": "Unsupported Media Type", "exception": "org.springframework.web.HttpMediaTypeNotSupportedException", "message": "Content type 'multipart/form-data;boundary=----WebKitFormBoundaryTVc9eDC2a2elulOx;charset=UTF-8' not supported", "path": "/upload"
解决方案:
去掉 @RequestBody 注解就行了
原因: 使用在进行图片或者文件上传时 multipart/form-data 类型时、 数据会自动进行映射不要添加任何注解。
加了@RequestBody后,所以参数都会转换成JSON,会影响 POST中上报数据流的格式
https://www.cnblogs.com/yueli/p/7552888.html
关键词:理解 http 消息头
使用 multipart form-data 上传 文件
以前的章节已经介绍过了form传输表单的形式,但是在使用过程中仍然有很多问题,这里再向大家详细介绍一下。
multipart/form-data是上传文件的一种方式。multipart/form-data其实就是浏览器用表单上传文件的方式。
最常见的情境是:在写邮件时,向邮件后添加附件,附件通常使用表单添加,也就是用multipart/form-data格式上传到服务器。
具体的步骤如下:
1、客户端和服务器建立链接(tcp协议)
2、客户端可以向服务器发送数据
3、客户端按照符合multipart/form-data的格式发送数据
post /top/router/rest ?timestamp=2013-05-24%2010%3a14%3a48&method=taobao.item.update&title=title%20998&session=610231517b65e4e4e82575817e2d9169eeaac271cb91c55378591009&app_key=10011050&v=2.0&num_iid=13068812771&format=js on&sign=6570c00315a94edac47414b6e9b681e0 http/1.0
content-type: multipart/form-data; boundary=——webkitformboundaryx3mhup4uhvo8zy3o
accept-charset: utf-8
host: gw.api.taobao.com
connection: close
content-length: 58294
——–webkitformboundaryx3mhup4uhvo8zy3o
content-disposition: form-data; name=”image”; filename=”pathddd.jpg”
content-type: image/gif
……jfif………….c…………………………….省略的图片文件信息
——–webkitformboundaryx3mhup4uhvo8zy3o–
解释说明
content-type: multipart/form-data; boundary=——webkitformboundaryx3mhup4uhvo8zy3o
说明的是multipart/form-data格式的请求,boundary是一个字符串,用来切分数据。
仔细查看,会发现body里面的bounday比header里面的前面都多了“–”。这是一个坑,我被搬到过。
需要注意的是,在html协议中换行使用的是:”
“,这我也被绊倒过。
下面是lua拼写的上传服务器的代码:
body = “——–webkitformboundaryx3mhup4uhvo8zy3o
content-disposition: form-data; name=”image”; filename=”path\ddd.jpg”
content-type: image/gif
” .. body;
body = body .. ”
——–webkitformboundaryx3mhup4uhvo8zy3o–
“;
搜索此文相关文章:理解HTTP消息头 五——使用multipart/form-data上传文件
此文链接:http://www.makaidong.com/%E5%8D%9A%E5%AE%A2%E5%9B%AD%E6%90%9C/30170.shtml
postman进行访问服务器时,使用浏览器的url可以正常返回结果,但是postman却显示Could not get any response
Could not get any response This seems to be like an error connecting to http://pc.oma.com:9090/oma/venue/updateVenue. Why this might have happened: The server couldn't send a response: Ensure that the backend is working properly SSL connections are being blocked: Fix this by importing SSL certificates in Chrome Cookies not being sent: Use the Postman Interceptor extension Request timeout: Change request timeout in Settings > General
解决办法:
关闭防火墙。
https://blog.csdn.net/sunny_12138/article/details/79196107
最新评论