Ajax应用最主要的特点是通过脚本操纵HTTP和Web服务器来传输数据,不会发生页面重载。可以仅向服务器发送并取回必须的数据,并在客户端通过JavaScript回应处理服务端的内容。
优点:因浏览器和服务器之间交换数据减少了,回应速度更快,同时Web服务器的负荷也减小了。
js封装ajax请求
import {Loading} from 'element-ui';
import {messageInfo} from '~/untils/message'
import * as types from '../store/mutation-Types';
import store from '../store/store';
//装饰者模式:给对象动态的添加某一些职责
Function.prototype.before = function(beforeFn) {
let _self = this;
return function() {
beforeFn.apply(this.arguments);
_self.apply(this.arguments);
}
}
Function.prototype.after = function(afterFn) {
let _self = this;
return function() {
_self.apply(this, arguments);
afterFn.apply(this, arguments);
}
}
/*
*@param settings 请求参数模仿jQuery ajax
* 调用该方法,data参数需要和请求头Content-Type对应
*/
const http = {
queue: {}, //请求队列,用来收集ajax请求
loading: function() {
var loading = Loading.service({
text: '正在努力加载中...',
background:'rgba(0,0,0,0.6)'
});
return loading;
},
//数据处理之字符串地址拼接
getURLString: (url, data) => {
if (!data) return '';
let urlStr = data instanceof Object ? http.getQueryData(data) : data;
if (url.indexOf('?') !== -1) {
return urlStr;
} else {
return '?' + urlStr;
}
},
//数据处理之数据类型判断
getQueryData: (data) => {
if(!data) return;
if(typeof data === 'string' || data instanceof FormData){
return data
};
return http.getQueryString(data);
},
//数据处理之对象转成字符串
getQueryString: (data) => {
let arrString = [];
if (data instanceof Object) {
Object.keys(data).forEach(item => {
let val = data[item];
arrString.push(encodeURIComponent(item) + '=' + encodeURIComponent(val));
})
}
return arrString.join('&');
},
//将json对象转成json字符
getJsonStr:(data)=>{
return JSON.stringify(data);
},
ajax: (settings = {}) => {
let _obj = Object.assign({
url: '', //请求地址
type: '', //请求类型 get post delete ...
dataType: 'json', //返回的数据类型为json格式
async: true, //是否异步,默认异步true
data: null, //请求所需的参数
headers: {}, //请求头
timeout: 5000, //多少时间设为超时
beforeSend: (xhr) => {}, //请求之前做什么
success: (result, status, xhr) => {}, //成功之后做什么
complete: (xhr, status) => {}, //请求完成之后做什么
error: (xhr, status, error) => {}, //请求错误做什么
}, settings)
if (!_obj.url || !_obj.type || !_obj.dataType || !_obj.async) {
messageInfo.messageInfo({
type: 'error',
content: '参数错误',
duration: 0
})
return;
}
//创建xhr对象 兼容各个浏览器
let xhr;
if (typeof XMLHttpRequest !== 'undefined') {
xhr = new XMLHttpRequest();
} else if (window.ActiveXObject) {
let aVersions = ["Msxml2.XMLHttp.5.0", "Msxml2.XMLHttp.4.0", "Msxml2.XMLHttp.3.0", "Msxml2.XMLHttp",
"Microsoft.XMLHttp"
];
for (var i = 0, items = aVersions.length; i < items; i++) {
try {
xhr = new ActiveXObject(aVersions[i]);
break;
} catch (e) {
}
}
}
//是否携带跨域信息
xhr.withCredentials = true;
//监听请求之前
xhr.addEventListener('loadstart', (e) => {
_obj.beforeSend(xhr);
});
//监听请求时
xhr.addEventListener('load', (e) => {
const status = xhr.status;
if (status >= 200 && status < 300 || status === 304) {
let result;
switch (xhr.responseType) {
case 'text':
result = xhr.responseText;
case 'document':
result = xhr.responseXML;
default:
result = xhr.response;
}
_obj.success(result, status, xhr);
} else {
_obj.error(xhr, status, e);
}
});
//监听请求完成时
xhr.addEventListener('loadend', (e) => {
_obj.complete(xhr, xhr.status);
});
//监听请求错误
xhr.addEventListener('error', (e) => {
_obj.error(xhr, xhr.status, e);
})
//监听请求超时
xhr.addEventListener('timeout', (e) => {
_obj.error(xhr, 408, e);
});
//send函数是发送null,还是数据的标识判断
let useURLString = false;
let sType = _obj.type.toUpperCase();
if (sType === 'GET' || sType === 'DELETE') {
useURLString = true;
_obj.url += http.getURLString(_obj.url, _obj.data);
}
//打开请求,在发送请求头时务必要打开请求。
xhr.open(_obj.type, _obj.url, _obj.async);
//设置响应的数据格式
xhr.responseType = _obj.dataType;
//设置请求头
for (const key of Object.keys(_obj.headers)) {
if(_obj.headers[key]){
xhr.setRequestHeader(key, _obj.headers[key]);
}
}
//设置超时时间
if (_obj.async && _obj.timeout) {
xhr.timeout = _obj.timeout;
}
//发送数据,当为get delete请求时发送null 否则数据处理
xhr.send(useURLString?null:Object.values(_obj.headers).join('').indexOf('application/json')!==-1?http.getJsonStr(_obj.data):http.getQueryData(_obj.data));
},
request: (settings = {}) => {
//错误处理函数
let errorHandler = (xhr, status) => {
if (status === 401) {
messageInfo.messageInfo({
type: 'error',
content: '没有权限',
duration: 0
})
} else if (status === 408) {
messageInfo.messageInfo({
type: 'error',
content: '连接超时',
duration: 0
})
}
};
//在执行错误函数之前 拦截错误信息执行函数
settings.error = (settings.error || function() {}.before((xhr, status, e) => {
delete http.queue[settings.url];
if (Object.keys(http.queue).length === 0) {
http.loading().close();
}
errorHandler(xhr, status);
}));
//在发送请求之前 开启loading...图标
settings.beforeSend = (settings.beforeSend || function() {}.before(() => {
if (Object.keys(http.queue).length === 0) {
http.loading();
}
http.queue[settings.url] = settings.url;
}));
//在数据请求完毕 关闭loading...图标
settings.complete = (settings.complete || function() {}.after(() => {
delete http.queue[settings.url];
if (Object.keys(http.queue).length === 0) {
http.loading().close();
}
}));
//请求成功的同一处理
let successFn = settings.success;
settings.success = (result, status, xhr) => {
//兼容ie
var res;
if (typeof result === 'string') {
res = JSON.parse(result)
} else {
res = result;
}
//登入接口设置
if (res.type === 'signin') {
successFn && successFn(res, status, xhr);
return;
}
//统一处理接口code不等于200的问题
if (!(res.code == 0 || res.code == 200)) {
messageInfo.messageInfo({
type: 'error',
content: result.message && result.message!=null?result.message:result.data&&result.data!=null?result.data:'接口请求发生错误!',
duration: 0
})
} else {
successFn && successFn(res, status, xhr);
}
};
// (http.ajax.before(addAuthorizationHeader)(settings));
http.ajax(settings);
},
// 自定义请求头、添加权限请求头
addAuthorizationHeader: (settings) => {
settings.headers = settings.headers || {};
const headerKey = 'Authorization'; // todo 权限头名称
// 判断是否已经存在权限header
let hasAuthorization = Object.keys(settings.headers).some(key => {
return key === headerKey;
});
if (!hasAuthorization) {
settings.headers[headerKey] = 'test'; // todo 从缓存中获取headerKey的值
}
},
get: (url, option = {}, dataType = 'json') => {
return new Promise((resolve, reject) => {
http.request({
url: url,
type: 'GET',
dataType: dataType,
data: option.data,
success: (res, status, xhr) => {
resolve(res,status, xhr);
},
complete: option.complete,
error: (xhr, status, e) => {
reject(xhr, status, e);
},
headers: {
// 'Content-Type': option.contentType //data数据格式要&字符串
},
})
})
},
delete: (url, option = {}, dataType = 'json') => {
return new Promise((resolve, reject) => {
http.request({
url: url,
type: 'DELETE',
dataType: dataType,
data: option.data,
success: (res, status, xhr) => {
resolve(res, status, xhr);
},
complete: option.complete,
error: (xhr, status, e) => {
reject(xhr, status, e);
},
})
})
},
// 调用此方法,参数data应为查询字符串或普通对象
post: (url, option = {}, dataType = 'json') => {
return new Promise((resolve, reject) => {
http.request({
url: url,
type: 'POST',
dataType: dataType,
data: option.data,
headers: {
// 'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8' //data数据格式要&字符串
'Content-Type':false,
},
success: (res, status, xhr) => {
resolve(res, status, xhr);
},
complete: option.complete,
error: (xhr, status, e) => {
reject(xhr, status, e);
},
});
})
},
// 调用此方法,参数data应为json字符串
postBody: (url, option = {}, dataType = 'json') => {
return new Promise((resolve, reject) => {
http.request({
url: url,
type: 'POST',
dataType: dataType,
data: option.data,
headers: {
'Content-Type': 'application/json' //data数据格式json格式
},
success: (res, status, xhr) => {
resolve(res, status, xhr);
},
complete: option.complete,
error: (xhr, status, e) => {
reject(xhr, status, e);
},
});
})
}
}
export default http;
以上的代码就完成了,在vue项目中的main.js文件引入代码即可使用。