先说一下平时工作的情况:
日常的工作业务中,与后端数据交互只用了两种形式,GET
和POST
,写业务代码的时候传的参数都是对象格式{name:'jason',age:27}
,一般都是这样写:
Http.get('api/userCenter/bookList.json', {
date: '2010',
lang: 'en'
}).then(function(res) {
console.log(res);
})
Http.post('api/userCenter/login.json', {
mobile: 13821863666,
psd: 123123
}).then(function(res) {
console.log(this);
})
GET
传输时,需要把对应的参数拼接在URL的后面;POST
传输时,send的数据格式也主要只用到了以下三种:
-
Content-Type: application/x-www-form-urlencoded
,send(data)中的data数据格式为"name=jason&age=27"
,此时需要序列化参数对象 -
Content-Type: application/json
,send(data)中的data数据格式为"{"mobile":13821863666,"psd":123123}"
,此时需要用JSON.stringify()
把参数对象转换成json字符串 - 使用
FormData
对象,直接send(FormDataObj)即可,此时不需要设置Content-Type
我就针对以上这些应用场景对ajax做了简单的封装,代码如下:
// http.js
// note:xhr的兼容写法
// function XHR() {
// if (window.XMLHttpRequest) return new XMLHttpRequest();
// if (window.ActiveXObject) return new ActiveXObject('Microsoft.XMLHTTP');
// return 'Not support XMLHttpRequest!';
// }
// 判断是否为纯对象,比如这种格式 {'name': 'jason'} 是纯对象,函数、数组等则不是
function isPlainObject(obj) {
return Object.prototype.toString.call(obj) === '[object Object]';
}
// 查询字符串中每个参数的名称和值都必须使用 encodeURIComponent() 进行编码,然后才能放到 URL 的末尾;
// 所有名-值对儿都必须由和号 ( & ) 分隔
function addURLParam(url, name, value) {
url += (url.indexOf('?') == -1 ? '?' : '&');
url += encodeURIComponent(name) + '=' + encodeURIComponent(value);
return url;
}
/**
* Converts an object to x-www-form-urlencoded serialization.
* http://victorblog.com/2012/12/20/make-angularjs-http-service-behave-like-jquery-ajax/
* @param {Object} obj
* @return {String}
*/
function serialize(obj) {
var query = '', name, value, fullSubName, subName, subValue, innerObj, i;
for (name in obj) {
value = obj[name];
if (value instanceof Array) {
for (i = 0; i < value.length; ++i) {
subValue = value[i];
fullSubName = name + '[' + i + ']';
innerObj = {};
innerObj[fullSubName] = subValue;
query += serialize(innerObj) + '&';
}
}
else if (value instanceof Object) {
for (subName in value) {
subValue = value[subName];
fullSubName = name + '[' + subName + ']';
innerObj = {};
innerObj[fullSubName] = subValue;
query += serialize(innerObj) + '&';
}
}
else if (value !== undefined && value !== null)
query += encodeURIComponent(name) + '=' + encodeURIComponent(value) + '&';
}
return query.length ? query.substr(0, query.length - 1) : query;
}
function ajax(type, url, data, contentType) {
return new Promise(function(resolve, reject) {
var xhr = new XMLHttpRequest();
if (type.toUpperCase() === 'GET' && data) {
for (key in data) {
if (data.hasOwnProperty(key)) {
url = addURLParam(url, key, data[key]);
}
}
}
/** post传输,当传FormData类型的数据时,不需要设置Content-Type
* 当数据格式为纯对象时
* 默认设置'Content-Type'为'application/x-www-form-urlencoded',对数据进行序列化
* 如果'Content-Type'设置为'application/json',数据直接传json字符串
**/
if (type.toUpperCase() === 'POST' && isPlainObject(data)) {
if (!contentType || contentType === 'application/x-www-form-urlencoded') {
xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
data = serialize(data);
} else {
xhr.setRequestHeader('Content-Type', 'application/json');
data = JSON.stringify(data);
}
}
xhr.open(type, url, true);
xhr.onload = function() {
if ((xhr.status >= 200 && xhr.status < 300) || xhr.status == 304) {
var res = JSON.parse(xhr.response);
resolve(res);
} else {
reject(xhr.statusText);
}
};
xhr.timeout = 10000;
xhr.ontimeout = function() {
reject('链接超时!')
};
xhr.onerror = function() {
reject('网络错误!');
};
xhr.onabort = function() {
reject('请求取消!');
};
xhr.send(type.toUpperCase() === 'GET' ? null : data); // 如果不需要通过请求主体发送数据,则必须传入null,因为这个参数对有些浏览器来说是必需的
});
}
export default {
get: function(url, data) {
return ajax('GET', url, data);
},
post: function(url, data, contentType) {
return ajax('POST', url, data, contentType);
}
}
之后就可以在其他文件中使用get
和post
这两个接口:
import Http from 'http'
Http.get('api/userCenter/bookList.json', {
date: '2010',
lang: 'en'
}).then(function(res) {
console.log(res);
})
Http.post('api/userCenter/login.json', {
mobile: 13821863666,
psd: 123123
}).then(function(res) {
console.log(this);
})
get
的使用形式是Http.get(url, data)
;post
的使用形式是Http.post(url, data, contentType)
,第三个参数contentType
可选,当设置了对应的值时,http.js会对传入的参数做不同格式化的处理。