再谈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