其他网址
HTTP content-type | 菜鸟教程
POST提交数据之---Content-Type的理解; - 龙恩0707 - 博客园
简介
form表单中可以定义enctype属性,该属性的含义是在发送到服务器之前应该如何对表单数据进行编码。默认的情况下,表单数据会编码为"application/x-www-form-unlencoded"。
1 2 3 | <form method="post" action="show-data.php" enctype="multipart/form-data"> ... </form> |
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 :
另外一种常见的媒体格式是上传文件之时使用的:
- multipart/form-data : 需要在表单中进行文件上传时,就需要使用该格式
上面的Content-Type,我们只认得就好,但是下面有4种是需要我们清楚他们的区别及牢记在心的。
application/x-www-form-urlencoded
简介
特点
- 支持GET/POST等方法。
如果请求类型type是GET的话,那么格式化的字符串将直接拼接在url后发送到服务端; 如果请求类型是POST, 那么格式化的字符串将放在http body的Form Data中发送。- 所有数据变成键值对的形式 key1=value1&key2=value2的形式
- 特殊字符需要转义成utf-8编号,如空格会变成 %20;
- 所有浏览器都支持
作用:
1:最常见的POST提交数据方式。
2:原生form默认的提交方式(可以使用enctype指定提交数据类型)。
3:jquery,zepto等默认post请求提交的方式。
form表单中post默认提交方式的数据
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | <!DOCTYPE html> <html> <head> <title></title> <meta charset="utf-8"> <meta name="viewport" content="width=device-width,initial-scale=1.0,maximum-scale=1.0,user-scalable=0"> </head> <body> <div id="app"> <form action="http://www.example.com" method="POST"> <p>username: <input type="text" name="fname" /></p> <p>age: <input type="text" name="age" /></p> <input type="submit" value="提交" /> </form> </div> </body> </html> |
请求转化:
使用ajax的方式提交
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 | <!DOCTYPE html> <html> <head> <title></title> <meta charset="utf-8"> <meta name="viewport" content="width=device-width,initial-scale=1.0,maximum-scale=1.0,user-scalable=0"> <script type="text/javascript" src="//i2.wp.com/tugenhua0707.github.io/html5UploadImage/js/jquery.js"></script> </head> <body> <div id="app"> <div class="btn">发送post请求</div> </div> <script> var obj = { "name": 'CntChen', "info": 'Front-End', }; $('.btn').click(function() { $.ajax({ url: 'www.example.com', type: 'POST', dataType: 'json', data: obj, success: function(d) { } }) }); </script> </body> </html> |
转化之后:
multipart/form-data
简介
特点
- 使用表单上传文件时,必须指定表单的 enctype属性值为 multipart/form-data。
- 请求体被分割成多部分,每部分使用 --boundary分割;
注意事项
此时用request.getParameter是取不到数据的,这个时候需要通过request.getInputStream来获取数据。这时取到的是一个InputStream,无法直接取到指定的表单项。但是有很多开源的组件可以直接利用,比如apache的fileupload组件。通过这些开源的upload组件,提供的api,就可以直接从request中取得指定的表单项:
1
2 ServletFileUpload upload = new ServletFileUpload(factory);
List<FileItem> list = upload.parseRequest(request);上面的代码中,接下来就可通过遍历list获取参数了。
实例
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | <!DOCTYPE html> <html> <head> <title></title> <meta charset="utf-8"> <meta name="viewport" content="width=device-width,initial-scale=1.0,maximum-scale=1.0,user-scalable=0"> </head> <body> <div id="app"> <form action="http://www.example.com" method="POST" enctype="multipart/form-data"> <p>username: <input type="text" name="fname" /></p> <p>age: <input type="text" name="age" /></p> <input type="submit" value="提交" /> </form> </div> </body> </html> |
转化之后
application/json
简介
问题引出
http请求中,ContentType都是默认的值 application/x-www-form-urlencoded, 这种编码格式的特点是:name/value值对,每组之间使用&连接,而name与value之间是使用 = 连接,比如 key=xxx&name=111&password=123456; 键值对一般的情况下是没有什么问题的,是很简单的json形式,比如如下:
1
2
3
4 {
a: 1,
b: 2
}它会解析成 a=1&b=2这样的,但是在一些复杂的情况下,比如需要传一个复杂的json对象,也就是对象嵌套数组的情况下,比如如下代码:
1
2
3
4
5
6
7
8 {
obj: [
{
"name": 111,
"password": 22
}
]
}这样复杂的对象,application/x-www-form-urlencoded这种形式传递的话, 会被解析成 obj[0]['name']=111&obj[0].['password']=2这样的。然后再转成json形式;
对于一些复杂的数据对象,对象里面再嵌套数组的话,建议使用application/json传递比较好,开发那边也会要求使用application/json。因为他们那边不使用application/json的话,使用默认的application/x-www-form-urlencoded传递的话,开发那边先要解析成如上那样的,然后再解析成json对象,如果对于比上面更复杂的json对象的话,那么他们那边是很难解析的,所以直接json对象传递的话,对于他们来说更简单。
通过json的形式将数据发送给服务器。json的形式的优点是它可以传递结构复杂的数据形式,比如对象里面嵌套数组这样的形式等。
实例
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 | <!DOCTYPE html> <html> <head> <title></title> <meta charset="utf-8"> <meta name="viewport" content="width=device-width,initial-scale=1.0,maximum-scale=1.0,user-scalable=0"> <script type="text/javascript" src="//i2.wp.com/tugenhua0707.github.io/html5UploadImage/js/jquery.js"></script> </head> <body> <div id="app"> <div class="btn">发送post请求</div> </div> <script> $('.btn').click(function() { $.ajax({ url: 'http://www.example.com', type: 'POST', dataType: 'json', contentType: 'application/json', data: JSON.stringify({a: [{b:1, a:1}]}), success: function(d) { } }) }); </script> </body> </html> |
如上代码,在浏览器运行后,发现跨域了,如下图所示:
理解ajax跨域设置 ContentType: application/json
在使用ajax跨域请求时,如果设置Header的ContentType为 application/json,它会发两次请求,第一次先发Method为OPTIONS的请求到服务器,这个请求会询问服务器支持那些请求方法(比如GET,POST)等。如果这个请求支持跨域的话,就会发送第二个请求,否则的话在控制台会报错,第二个请求不会请求。如下我们做个简单的demo,不跨域的如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 | <!DOCTYPE html> <html> <head> <title></title> <meta charset="utf-8"> <meta name="viewport" content="width=device-width,initial-scale=1.0,maximum-scale=1.0,user-scalable=0"> <script type="text/javascript" src="//i2.wp.com/tugenhua0707.github.io/html5UploadImage/js/jquery.js"></script> </head> <body> <div id="app"> <div class="btn">发送post请求</div> </div> <script> $('.btn').click(function() { $.ajax({ url: 'http://localhost:8081/api.json', type: 'POST', dataType: 'json', contentType: 'application/json', data: JSON.stringify({a: [{b:1, a:1}]}), success: function(d) { } }) }); </script> </body> </html> |
如下图所示(json格式提交的数据会显示 Request Payload):
application/xml 和 text/xml
XML 麻烦,推荐用 JSON 。
XML(Extensible Markup Language) 是 SGML(Standard Generalized Markup Language)的一个子集。SGML 也分配了媒体类型( text/sgml 和 application/sgml),但兼容性较差。XML 有两种 MIME 媒体类型:text/xml 和 application/xml。
RFC2376 文档 定义了application/xml 和 text/xml 媒体类型。
RFC7303 文档 也定义了application/xml 媒体类型。
RFC3023 文档 一次定义了application/xml 和 text/xml 等所有的 XML 相关媒体类型。
application/xml 媒体类型
推荐使用。如果 MIME 用户代理或 Web 用户代理不支持这个媒体类型,会转为 application/octet-stream,当做二进制流来处理。application/xml 实体默认用 UTF-8 字符集。Content-type: application/xml; charset="utf-8" 或 都可以生效。
text/xml 媒体类型
如果 MIME 用户代理或 Web 用户代理不支持这个媒体类型,会将其视为 text/plain,当做纯文本处理。text/xml 媒体类型限制了 XML 实体中可用的编码类型(例如此时支持 UTF-8 但不支持 UTF-16,因为使用 UTF-16 编码的文本在处理 CR,LF 和 NUL 会导致异常转换)。text/xml 实体在 XML 头指定编码格式无效,必须在 HTTP 头部的 Content-Type: 中指定才会生效(例如 无法设置字符集,Content-Type: text/xml; charset="utf-8" 则可以)。没有设置字符集时默认使用“us-ascii”字符集。
Content-Type的使用
request 的Content-Type
一般我们在开发的过程中需要注意客户端发送请求(Request)时的Content-Type设置,特别是使用ajax的时候,如果设置得不准确,很有可能导致请求失败。比如在spring中,如果接口使用了@RequestBody,spring强大的自动解析功能,会将请求实体的内容自动转换为Bean,但前提是请求的Content-Type必须设置为application/json,否正就会返回415错误。
注:415 错误是 Unsupported media type,即不支持的媒体类型。
建议:
如果是一个restful接口(json格式),一般将Content-Type设置为application/json; charset=UTF-8;
如果是文件上传,一般Content-Type设置为multipart/form-data
如果普通表单提交,一般Content-Type设置为application/x-www-form-urlencoded
response的Content-Type
服务端响应(Response)的Content-Type最好也保持准确,虽然一般web开发中,前端解析响应的数据不会根据Content-Type,并且服务端一般能自动设置准确的Content-Type,但是如果乱设置某些情况下可能会有问题,比如导出文件,打开图片等。如果在spring项目里使用@ResponseBody,spring会将响应的Content-Type设置为application/json;charset=UTF-8;,可能会导致文件无法导出,需要注意下。
response的Content-Type设置建议:
一般情况下不需要显示设置;
如果是文件导出,Content-Type 设置为 multipart/form-data,并且添加一个Content-Disposition设置为attachment;fileName=文件.后缀。
注:Content-Disposition是Content-Type的扩展,告诉浏览器弹窗下载框,而不是直接在浏览器里展示文件。因为一般浏览器对于它能够处理的文件类型,如txt,pdf 等,它都是直接打开展示,而不是弹窗下载框。
下面的一个设置response的Content-Type的例子:
未准确设置response的Content-type的情况,客户端将json数据当成普通文本
content-type →text/html;charset=UTF-8
准确设置response的Content-type的情况,客户端将json数据自动解析
content-type →application/json;charset=UTF-8