wasabi-api
Version:
319 lines (273 loc) • 9.72 kB
JavaScript
/**
* Created by wangzhiyong on 2016-09-20.
* 后端接口对接
* edit by wangzhiyong
* date:2016-10-04,将ajax直接改用原生xhr
* date;2016-10-05 将rest独立出来,将格式化参数方法独立出来
** date;2016-11-05 验证可行性修改
** date;2017-01-14 验证可行性再次修改
* date:2017-04-18 修改在IE8,与360中的bug
* date:2017-06-16 修改asnyc参数的配置
* date:2017-07-01?增加headers参数
* date:2017-07-07 完善一些注释,完善一些逻辑
* date 2017-07-11 去掉一个错误的引用
* date:2017-07-13 完善语法
* * @description date:2018-01-15 修复bug,增加返回header
* date:2020-04-27 desc 修改错误方法参数,只回传错误消息
*date:2020-09-22 desc 还是超时bug
*date:2020-11-09 desc 修复超过的bug,及同步bug
date 2021-01-27 去掉ajax中的cookie,保证安全
date:2021-03-27 修复状态值的bug
date:2021-09-16 修复错误提示
* 使用方法
* ajax({
url:"http://localhost:7499/Admin/Add",
type:"post",
data:{name:"test",password:"1111",nickname:"dddd"},
success: (result)=>{
console.log(result);
},
error:(meesage)=>{
}
})
*/
import httpCode from "./httpCode.js";
import paramFormat from "./paramFormat.js";
import validate from "./validate";
/**
* ajax请求
*/
export default function (settings) {
let xhrRequest = createXHR();//创建xhr对象
if (!validate(settings)) {//验证有效性
return;
}
if (xhrParamsSet()) { //设置参数
//开始发送数据
if (settings.data) { //有参数
if (settings.type.toLowerCase() == "get") { //如果是get
xhrRequest.send();
} else { //post/put等
xhrRequest.send(settings.data);
}
} else {
xhrRequest.send();
}
} else {
}
/**
* 创建xhr对象
* @returns {oject}
*/
function createXHR() {
let xhr;
if (window.XMLHttpRequest) {
xhr = new XMLHttpRequest();
} else {
xhr = new ActiveXObject('Microsoft.XMLHTTP');
}
return xhr;
}
/**
* xhr参数设置
*/
function xhrParamsSet() {
//格式化参数
settings.data = paramFormat(settings.data);
//get方式时如果有data参数,则将参数追加到url中
if (settings.type.toLowerCase() == "get") {
if (settings.data && settings.url.indexOf("?") <= -1) {
settings.url += "?";
}
if (settings.data && settings.url.indexOf("?") > -1 && settings.url.indexOf("?") == settings.url.length - 1) {
settings.url += settings.data;
} else if (settings.data && settings.url.indexOf("?") > -1 && settings.url.indexOf("?") < settings.url.length - 1) {
settings.url += "&" + settings.data;
}
}
try {
xhrRequest.open(settings.type, settings.url, settings.async);
} catch (e) { //说明不支持跨域
errorHandler(803, "[IE,360]自动阻止了跨域:" + e.message);
}
//设置请求格式
if (settings.contentType == false) { //为false,不设置Content-Type
} else {
xhrRequest.setRequestHeader("Content-Type", settings.contentType); //请求的数据格式,
}
//设置返回格式
try {
xhrRequest.responseType = settings.dataType; //回传的数据格式
} catch (e) {
console.log("该浏览器[IE,360]不支持responseType的设置,跳过");
}
//todo 为了安全起见先去掉再说
// try {
// xhrRequest.withCredentials = settings.cors ? true : false; //表明在进行跨站(cross-site)的访问控制(Access-Control)请求时,是否使用认证信息(例如cookie或授权的header)。 默认为 false。
// } catch (e) {
// console.log("该浏览器[IE,360]不支持withCredentials的设置,跳过");
// }
if (settings.timeout && settings.async !== false) { //设置超时时间
xhrRequest.timeout = settings.timeout; //超时时间
}
//设置headers
if (settings.headers instanceof Object) {
try {
for (let prop in settings.headers) {
xhrRequest.setRequestHeader(prop, encodeURI(settings.headers[prop]));//防止无法传输中文
}
} catch (e) {
throw new Error(e.message);
}
}
try {
//支持xhr2.0
xhrRequest.addEventListener("load", load, false); ///执行成功事件
xhrRequest.addEventListener("loadend", loadEnd, false); //执行完成事件
xhrRequest.addEventListener("timeout", timeout, false); //超时事件
xhrRequest.addEventListener("error", error, false); //执行错误事件
xhrRequest.upload.addEventListener("progress", progress, false); //上传进度
} catch (e) { //说明不支持xhr2.0
console.log("浏览器不支持xhr2.0,已经转为1.0");
xhrRequest.onreadystatechange = function () {
if (xhrRequest.readyState == 4) {
let e = {};
e.target = xhrRequest;
load(e); //调用加载成功事件
}
}
}
return true;
}
/**
* 上传进度事件
* @param event
*/
function progress(event) {
if (event.lengthComputable) {
let percentComplete = Math.round(event.loaded * 100 / event.total);
if (typeof settings.progress === "function") {
settings.progress(percentComplete); //执行上传进度事件
}
else {
}
}
}
/**
* 请求成功
* @param event
*/
function load(event) {
let xhr = (event.target);
if (xhr.readyState == 4 && ((xhr.status >= 200 && xhr.status < 300) || xhr.status == 304)) { //请求成功
let headers = xhrRequest.getAllResponseHeaders();//后台的头部信息
if (settings.dataType == "json") {
//json格式请求
let result = xhr.response ? xhr.response : xhr.responseText; //1.0
if (result) {
if (typeof result == "string") { //IE8.360 中没有对结果进行JSON化
result = JSON.parse(result);
}
//下面是判断常见的后端请求数据格式
if (result.success != null && result.success != undefined) {
/**
* 后端通过success参数判断执行是否成功,没有考虑登陆失效后自动跳转的情况
*/
if (result.success) {
settings.success(result, headers); //执行成功
} else {//请求失败
if (result.message) { //有标准的错误信息
errorHandler(result.statusCode || result.code || 801, result.message);
} else {
errorHandler(801, "服务器正常响应,后台业务代码的逻辑报错");
}
}
}
else if (result.statusCode || result.code || result.status || result.state) {
/**
* 后端通过statusCode【状态码】参数判断执行是否成功,考虑了登陆失效后自动跳转的情况,
* 通常是通过-1来判断,此处不作处理,不够通用
*
*/
/**
* 将几个常见的状态码情况统一为statusCode,因为code这个参数在小程序中请求时,代表http的状态码了
*/
result.statusCode = result.statusCode || result.code || result.status || result.state;
result.statusCode = result.statusCode * 1;//转成数字型
if (result.statusCode == 200 || result.statusCode == 1) {
settings.success(result, headers); //执行成功
} else {
if (result.message) { //有标准的错误信息
errorHandler(result.statusCode || result.code || 801, result.message);
} else {
errorHandler(801, "服务器正常响应,后台业务代码的逻辑报错");
}
}
}
else {
/**
* 其他后端接口模式,不作为处理,直接认为成功了
*/
settings.success(result, headers); //直接认为是成功的
}
} else {
errorHandler(802, "服务器返回的数据格式不正确");
}
} else if (settings.dataType == "blob" || settings.dataType == "arrayBuffer") { //二进制数据
settings.success(xhr.response, headers);
} else { //其他格式
try {
settings.success(xhr.responseText, headers);
} catch (e) { //如果没有responseText对象,不能通过if判断,原因不详
settings.success(xhr.response, headers);
}
}
} else {
//是4xx错误时属于客户端的错误,并不属于Network error,不会触发error事件
errorHandler(xhr.status, xhr.statusText);
}
}
/**
* 请求完成
* @param {*} event
*/
function loadEnd(event) {
let xhr = (event.target);
if (typeof settings.complete === "function") { //设置了完成事件,
if (xhr.readyState == 4 && ((xhr.status >= 200 && xhr.status < 300) || xhr.status == 304)) { //请求成功
//304客户端已经执行了GET,但文件未变化,认为也是成功的
settings.complete(xhr, "success");
} else if (xhr.readyState == 4 && xhr.status == 0) { //本地响应成功,TODO 暂时不知道如何处理
settings.complete(xhr, "success");
} else { //错误
settings.complete(xhr, "error");
}
}
}
/**
* 请求超时
* @param event
*/
function timeout(event) {
errorHandler(804, "请求超时");
}
/**
* 请求失败
* @param event
*/
function error(event) {
let xhr = (event.target);
//暂时通过这种方式来判断404错误
let message = httpCode[xhr.status.toString() || "404"];
errorHandler(xhr.statusText ? xhr.statusText : message, xhr.status);
}
/**
* 通用错误处理函数
* @param message 信息提示
* @param errCode 错误代码
*/
function errorHandler(message, errCode) {
console.error(message);
typeof settings.error === "function" ? settings.error(message, errCode) : void (0);
}
}