# Ajax方式提交表单的常见编码类型总结
用Ajax方式提交,决定编码类型的是请求头中 Content-Type ,不同值对应不同提交处理方式。
- application/x-www-form-urlencoded
- multipart/form-data
- text/plain
- application/json
- text/xml
# XMLHttpRequest 方式
后续代码将假设已经获得XMLHttpRequest对象,其名req。XMLHttpRequest对象用常见的五种Content-Type发送数据的方式。
application/x-www-form-urlencoded
这种Content-Type要求数据按照key1=value1&key2=value2的格式发送给后端,且其中的特殊字符需要转义成%HH的形式。其中HH表示该字符的十六进制ASCII码。例如,空格字符的ASCII码是32,所以它被转义成%20。
首先,需要用 encodeURIComponent() 函数编码表单数据,代码如下。
req.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
/* data参数为表单数据组成的对象,dataToSend为待发送给后端的数据 */
var tempArr = [];
for (var key in data) {
if (data.hasOwnProperty(key)) {
tempArr.push(encodeURIComponent(key) + '=' + encodeURIComponent(data[key]));
}
}
var dataToSend = tempArr.join('&');
//接着,设置请求头部的Content-Type,发送数据,代码如下。
req.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
req.send(dataTosend);
multipart/form-data
多用来提交文件,可采用H5的FormData对象来构建提交的数据。
现代浏览器都支持,IE11以下不支持,不支持的可以使用ajaxForm之类的jquery的文件提交插件。
/* data参数为表单数据组成的对象,dataToSend为待发送给后端的数据 */
var dataToSend = new FormData();
for (var key in data) {
if (data.hasOwnProperty(key)) {
dataToSend.append(key, data[key]);
}
}
// dataToSend就是FormData对象,可直接传给后端
//接着,直接发送给后端,注意这种类型的发送方式,
//不需设置请求头部的Content-Type,应交给浏览器来处理(设定Boundary等工作)。
req.send(dataToSend);
text/plain
如果请求头部没有设定Content-Type,且数据既不是FormData也不是XML Document,则Content-Type默认text/plain。
//这种方式的代码很简单,直接发送字符串即可。
req.send('xxxx');
application/json
JSON格式的数据,后端和移动端都很方便处理,用这种MIME类型时,需要将数据对象转换成JSON串。 首先,转换数据成JSON串;然后,设定请求头部的Content-Type,就可以发数据了。
/* data参数为表单数据组成的对象 */
req.send( JSON.stringify(data) );
text/xml
首先,构建XML文档对象,存入表单数据,代码如下。
/* data参数为表单数据组成的对象,dataToSend为待发送给后端的数据 */
var dataToSend = document.implementation.createDocument("", "formdata", null);
var tempData = dataToSend.documentElement;
for (var key in data) {
if (data.hasOwnProperty(key)) {
var keyElement = doc.createElement(key);
keyElement.appendChild(doc.createTextNode(data[key]));
tempData.appendChild(keyElement);
}
}
/*
xml文档格式示意:
<formdata>
<key1> value1 </key1>
<key2> value2 </key2>
</formdata>
*/
//之后,与multipart/form-data一样,直接发送数据,不需设置Content-Type。
req.send(dataToSend);
小结
multipart/form-data与text/xml不需要设置请求头的Content-Type; 关于method,以上都是POST方式,若是GET方式一般没有请求体,数据直接加在URL后面;
附:接收请求时的解析方式 text/xml:用responseXML application/json:需要先JSON化,JSON.parse( responseText ) 其他:就直接用responseText
# jQuery 方式
application/x-www-form-urlencoded
jQuery中默认的表单提交方式,与XMLHttpRequest不同的地方在于:数据的URL方式编码,由jQuery来做,只需要在$.ajax({})参数中设置processData = true(默认,可省略)。
/* dataToSend为Object类型的表单数据,否则jQuery会抛出异常 */
$.ajax({
method: 'POST',
url: '...',
data: dataToSend,
contentType: 'application/x-www-form-urlencoded', // 可省略
processData: true, // 可省略 对data参数进行序列化处理
success: function() {...}
});
// 注意:若采用GET方式,则将method改为GET即可,不需要在url后面加上数据。
multipart/form-data
/* dataToSend 是FormData对象,可直接作为数据传输到后端 */
var dataToSend= new FormData(); // HTML5对象, IE11以下不支持
for (var key in data) {
if (data.hasOwnProperty(key)) {
dataToSend.append(key, data[key]);
}
}
//之后,用$.ajax()方法传输数据。
//注意:processData与contentType必须设定为false,前者是因为避免FormData对象被转换成URL编码,
//后者则是因为需要浏览器添加multipart/form-data类型的boundary。
$.ajax({
method: 'POST',
url: '...',
data: dataToSend, // dataToSend 是FormData对象
contentType: false,
processData: false,
success: function() { ... }
});
text/plain
用该类型提交,则直接传输字符串。
$.ajax({
method: 'POST',
url: '...',
data: dataToSend,
contentType: 'text/plain',
processData: false, // processData 设置为false则不会转换成URL编码
success: function() { ... }
});
application/json 用该类型提交,则传输JSON字符串,所以要用函数JSON.stringify()处理表单数据。
/* data 为表单Object类型的数据 */
dataToSend = JSON.stringify(data);
$.ajax({
method: 'POST',
url: '...',
data: dataToSend,
contentType: 'application/json',
processData: false, // processData 设置为false则不会转换成URL编码
success: function() { ... }
});
//注意:若后端也返回JSON字符串时,success回调函数里接受到的数据参数仍为字符串,
//需要转换成Object类型。(而Angular,vue使用的axios也不需要)
$.ajax({
...
success: function(data) {
var jsonData = JSON.parse(data);
...
}
});
text/xml
首先,构建XML文档对象,存入表单数据,代码如下。
/* data参数为表单数据组成的对象,dataToSend为待发送给后端的数据 */
var dataToSend = document.implementation.createDocument("", "formdata", null);
var tempData = dataToSend.documentElement;
for (var key in data) {
if (data.hasOwnProperty(key)) {
var keyElement = doc.createElement(key);
keyElement.appendChild(doc.createTextNode(data[key]));
tempData.appendChild(keyElement);
}
}
/*
xml文档格式示意:
<formdata>
<key1> value1 </key1>
<key2> value2 </key2>
</formdata>
*/
//之后,发送数据dataToSend,代码如下。
$.ajax({
method: 'POST',
url: '...',
data: dataToSend,
contentType: false, // contentType 可设为false也可写成具体的'text/xml'等
processData: false, // processData 必须设为false
success: function() { ... }
});
# axios方式
先系统的默认axios的content-type的方式为application/x-www-form-urlencoded
import axios from 'axios'
import VueAxios from 'vue-axios'
axios.defaults.baseURL='http://xxxxx/xxx'
axios.defaults.headers.post['Content-Type'] = 'application/x-www-form-urlencoded';
Vue.prototype.$axios = axios;
# post
//post请求:
//需要安装qs模块
let postData = this.$qs.stringify({
name: that.name,
phone:that.tele,
password:md5pass,
});
this.$axios.post('/user/register',
postData
)
//JSON格式传
let postData={
bank:that.bank,
bankAccount:that.banknumber,
name:that.company
}
let config = {
headers: {'Content-Type': 'application/json'}
}
this.$axios.post('/invoice/insertInvoices',
postData,config
)
总结: get请求的数据一般放在地址栏里,以axios为例,可拼接在api后面也可以写在parsms里['/get12?id=19',{params:obj}]都在query string parameters。而post可能在formdata里(www格式和formdata文件时),也可能周期request payload中(application/json时)
# 关于multipart/form-data设置
对于multipart/form-data设置,博客上有要是用和不适用两种,通过试验,结论如下:
- 如果是form表单提交,则必须设置。
- 如果使用axios,则可以不设置,而且手动设置成其他类型,接口依旧能处理,且请求体Content-Type仍然是multipart/form-data
- 使用了element插件,自己手动设置了headers content-type:multipart/form-data,会出错
- 上传图片(Content-Type: multipart/form-data; boundary=----WebKitFormBoundary0iJj0hLz7qx5IKiM) boundary:自己设置contenttype在element就会没有
- 使用node服务器测试的,在java下也可以,其他未知!
- 当请求data未设置,axios会删除请求的content-type;
//npm下axios的源码中,当未设置requestData的时候会删掉Content-Type的设置
// Add headers to the request
if ('setRequestHeader' in request) {
utils.forEach(requestHeaders, function setRequestHeader(val, key) {
if (typeof requestData === 'undefined' && key.toLowerCase() === 'content-type') {
// Remove Content-Type if data is undefined
delete requestHeaders[key];
} else {
// Otherwise add header to the request
request.setRequestHeader(key, val);
}
});
}
// 假如后端非要这个熟悉的话,解决办法
service.interceptors.request.use(
config => {
config.data = JSON.stringify(config.data);
config.headers['Authorization'] = getToken();
config.data = true
config.headers[ 'Content-Type'] = "application/json;charset=utf-8";
return config;
},
error => {
return Promise.reject();
}
# contType在请求的时候设置
const data ={
visionId,
groupId:'2',
orgCategory:'0'
}
var tempArr =[]
for (var key in data) {
if (data.hasOwnProperty(key)) {
tempArr.push(encodeURIComponent(key) + '=' + encodeURIComponent(data[key]));
}
}
var dataToSend = tempArr.join('&');
this.cloudConfig.headers = {}
this.cloudConfig.headers['Content-Type'] ='application/x-www-form-urlencoded'
return this.http.Post(`/xxx`,dataToSend,this.cloudConfig)
//或者不需要配置cloudConfig,直接加载后面也可以
return this.http.Post(`/xxx?visionId=${visionId}&groupId='2'&orgCategory=${orgCategory}`,null,this.cloudConfig)