共计 3477 个字符,预计需要花费 9 分钟才能阅读完成。
HTTP 协定规定 POST 提交的数据必须放在音讯主体(entity-body)中,但协定并没有规定数据必须应用什么编码方式。实际上,开发者齐全能够本人决定音讯主体的格局,只有最初发送的 HTTP 申请满足下面的格局就能够。然而,数据发送进来,还要服务端解析胜利才有意义。个别服务端语言如 php、python 等,以及它们的 framework,都内置了主动解析常见数据格式的性能。
服务端通常是依据申请头(headers)中的 Content-Type 字段来获知申请中的音讯主体是用何种形式编码,再对主体进行解析。
所以说到 POST 提交数据计划,蕴含了 Content-Type 和音讯主体编码方式两局部。
POST 申请中,提交的数据放到音讯体中,并且提供了四种数据的编码方式。
FORM 表单的 enctype 属性规定在发送到服务器之前应该如何对表单数据进行编码。
默认地,表单数据会编码为 “application/x-www-form-urlencoded”。就是说,在发送到服务器之前,所有字符都会进行编码(空格转换为 “+” 加号,特殊符号转换为 ASCII HEX 值)。
四种 enctype 属性值
值 | 形容 |
---|---|
application/x-www-form-urlencoded | 在发送前编码所有字符(默认) |
multipart/form-data | 不对字符编码。在应用蕴含文件上传控件的表单时,必须应用该值。 |
application/json | |
text/plain | 空格转换为 “+” 加号,但不对特殊字符编码。 |
上面就正式开始介绍它们。
1.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 提交的申请数据,抓包时看到的申请会是这样的内容(无关的申请头在本文中都省略掉了):
POST
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」。
2.multipart/form-data
这又是一个常见的 POST 数据提交的形式。咱们应用表单上传文件时,必须让 <form> 表单的 enctype 等于 multipart/form-data。间接来看一个申请示例:
POST 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 进行数据交互之后,咱们齐全能够定义新的数据提交形式,给开发带来更多便当。
3.application/json
application/json 这个 Content-Type 作为响应头大家必定不生疏。实际上,当初越来越多的人把它作为申请头,用来通知服务端音讯主体是序列化后的 JSON 字符串。因为 JSON 标准的风行,除了低版本 IE 之外的各大浏览器都原生反对 JSON.stringify,服务端语言也都有解决 JSON 的函数,应用 JSON 不会遇上什么麻烦。
JSON 格局反对比键值对简单得多的结构化数据,
Google 的 AngularJS 中的 Ajax 性能,默认就是提交 JSON 字符串。例如上面这段代码:
JSvar data = {'title':'test', 'sub' : [1,2,3]};
$http.post(url, data).success(function(result) {...});
最终发送的申请是:
POST 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 形式提交数据。
4.text/xml
典型的 XML-RPC 申请是这样的:
POST 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>