再谈from属性EncType与axios封装—axios拦截与中断—源码浅析
Author:zhoulujun Date:
若干年前使用angular的时候,总结过《from属性EncType提交数据的格式详解—在angular中的应用》
在远古ie兴盛的时代,基本是fromData提交数据,ajax+jquery推动了时代的变革,当数据提交也大抵如此,直到angularJS到来,前后端才通用json形式,转眼从react跳转到vue(感觉被Vue强暴),闲话打住
axios.CancelToken
cancelToken可以取消axios请求,一般原生XMLHttpRequest ajax请求的话,用的是abort()这个方法。
推荐阅读文章:Vue切换页面时中断axios请求、axios 之cancelToken原理以及使用
var CancelToken = axios.CancelToken;
var source = CancelToken.source();
axios.get('/user/12345', {
//get请求在第二个参数,post请求在第三个参数
cancelToken: source.token
})
source.cancel('不想请求了');
get请求的时候,cancelToken是放在第二个参数里;post的时候,cancelToken是放在第三个参数里。
实现原理大致如下:
let resolveHandle;
new Promise((resolve)=>{
resolveHandle=resolve;
}).then((val)=>{
console.log('resolve',val);
});
resolveHandle('ok');
上面的例子中,我们用resolveHandle获取了一个promise的resolve方法的控制权,这样,我们就可以在外部控制这个promise的成功了。要知道new Promise返回的对象是无法从外部决定它成功还是失败的。axios中断请求方法也是劫持,具体看起源码。
axios.interceptors
理论上,一套api接口,一般统一json格式,要么统一fromData,但是,就是有不按套路出牌(后端屌啊),三个都有
application/x-www-form-urlencoded
multipart/form-data
application/json
同时,接口返回数据,理论上应该统一规划,比如消息属性(toast统一处理),数据分层,但是,泪崩
axios封装是必须,但是,前端时候也得考虑下规范(架构设计)方面的问题——小白秉性暴露无遗
看了axios源码
+axios
index.js
index.d.ts
+lib
axios.js
+core
Axios.js
axios本身就会检测数据,匹配不同Content-Type
transformRequest: [function transformRequest(data, headers) {
normalizeHeaderName(headers, 'Content-Type');
if (utils.isFormData(data) ||
utils.isArrayBuffer(data) ||
utils.isBuffer(data) ||
utils.isStream(data) ||
utils.isFile(data) ||
utils.isBlob(data)
) {
return data;
}
if (utils.isArrayBufferView(data)) {
return data.buffer;
}
if (utils.isURLSearchParams(data)) {
setContentTypeIfUnset(headers, 'application/x-www-form-urlencoded;charset=utf-8');
return data.toString();
}
if (utils.isObject(data)) {
setContentTypeIfUnset(headers, 'application/json;charset=utf-8');
return JSON.stringify(data);
}
return data;
}],
但是,实际提交都是 Object类型,于是就得转
第一种处理模式,就是prototype大法,
axios.postForm = function (url, data, config = null) {
return new Promise(function (resolve, reject) {
config = {
method: 'post',
url: url,
data: () => {
let fromData = new FormData();
for (let i in data) {
fromData.append(i,data[i])
}
return fromData;
}
};
axios.request(config).then((response) => {
resolve(response)
}, err => {
reject(err);
})
})
};
第二种,重新构造一个新的函数,call回调,或者
class http {
constructor(config) {
if (config) {
return new Promise((resolve, reject) => {
axios(config)
.then(function (response) {
});
});
}
}
static get(url, parma) {}
static post(url, param) {}
}
发现在var axios= Create an instance of Axios,axios get post request 都是集中处理
Axios.prototype.request
// Provide aliases for supported request methods
utils.forEach(['delete', 'get', 'head', 'options'], function forEachMethodNoData(method) {
/*eslint func-names:0*/
Axios.prototype[method] = function(url, config) {
return this.request(utils.merge(config || {}, {
method: method,
url: url
}));
};
});
utils.forEach(['post', 'put', 'patch'], function forEachMethodWithData(method) {
/*eslint func-names:0*/
Axios.prototype[method] = function(url, data, config) {
return this.request(utils.merge(config || {}, {
method: method,
url: url,
data: data
}));
};
});
于是决定,通过增加一个属性声明,如:commitType:'form'
于是,就会有如下代码
import axios from 'axios';
import queryString from 'queryString';//nodeJs内置,无需npm i
axios.interceptors.request.use(function (config) {
//TODO 请求拦截
/*store.commit('updateLoadingStatus', {isLoading: true});*/
if (config.commitType) {
if (config.commitType === 'form') {
config.headers['Content-Type'] = 'application/x-www-form-urlencoded';
config.transformRequest = [function (data) {
return queryString.stringify(data);//利用对应方法转换格式
}]
} else if (config.commitType === 'url') {
config.headers['Content-Type'] = 'application/x-www-form-urlencoded;charset=utf-8';
config.transformRequest = [function (data) {
return decodeURIComponent(data);
}];
}
}
console.log(config);
return config;
}, function (error) {
//请求错误时做些事
return Promise.reject(error);
});
//响应拦截器即异常处理
axios.interceptors.response.use(response => {
//TODO 统一处理逻辑
//store.commit('updateLoadingStatus', {isLoading: false});
if (response.data) {
return response.data;
}
return response
}, err => {
if (err && err.response) {
//http状态码处理
switch (err.response.status) {
case 400:
err.msg = '错误请求';
break;
case 401:
err.msg = '未授权,请重新登录';
break;
case 403:
err.msg = '拒绝访问';
break;
case 404:
err.msg = '请求错误,未找到该资源';
break;
case 405:
err.msg = '请求方法未允许';
break;
case 408:
err.msg = '请求超时';
break;
case 500:
err.msg = '服务器端出错';
break;
case 501:
err.msg = '网络未实现';
break;
case 502:
err.msg = '网络错误';
break;
case 503:
err.msg = '服务不可用';
break;
case 504:
err.msg = '网络超时';
break;
case 505:
err.msg = 'http版本不支持该请求';
break;
default:
err.msg = `连接错误${err.response.status}`
}
} else {
err.msg = '连接到服务器失败';
}
return Promise.resolve(err.response)
});
//超时时间
axios.defaults.timeout = 5000;
export default axios;
拓展文章:
Vue基于vuex、axios拦截器实现loading效果及axios的安装配置
转载本站文章《再谈from属性EncType与axios封装—axios拦截与中断—源码浅析》,
请注明出处:https://www.zhoulujun.cn/html/webfront/ECMAScript/vue/8137.html